คุณควรใส่ค่าคงที่ตรงไหนและทำไม?


34

ในแอปพลิเคชันขนาดใหญ่ส่วนใหญ่ของเราเรามักจะมีเพียงไม่กี่ตำแหน่งสำหรับ "ค่าคงที่":

  • หนึ่งคลาสสำหรับ GUI และค่าคงที่ภายใน (ชื่อแท็บหน้า, ชื่อกลุ่มกล่อง, ปัจจัยการคำนวณ, การแจกแจง)
  • หนึ่งคลาสสำหรับตารางและคอลัมน์ฐานข้อมูล (ส่วนนี้เป็นรหัสที่สร้างขึ้น) พร้อมชื่อที่อ่านได้สำหรับพวกเขา (กำหนดด้วยตนเอง)
  • คลาสหนึ่งสำหรับข้อความแอปพลิเคชัน (การบันทึกกล่องข้อความ ฯลฯ )

ค่าคงที่มักจะถูกแยกออกเป็นส่วนต่าง ๆ ในคลาสเหล่านั้น ในแอปพลิเคชัน C ++ ของเราค่าคงที่จะถูกกำหนดเฉพาะในไฟล์. h และค่าจะถูกกำหนดในไฟล์. cpp

ข้อดีอย่างหนึ่งก็คือสตริงทั้งหมด ฯลฯ อยู่ในจุดศูนย์กลางเดียวและทุกคนรู้ว่าจะต้องค้นหาสิ่งใดเมื่อต้องมีการเปลี่ยนแปลง

นี่เป็นสิ่งที่ผู้จัดการโครงการดูเหมือนจะเป็นอย่างที่ผู้คนเข้ามาและด้วยวิธีนี้ทุกคนสามารถเปลี่ยนแปลงสิ่งเล็ก ๆ น้อย ๆ ได้โดยไม่ต้องขุดเข้าไปในโครงสร้างของแอปพลิเคชัน

นอกจากนี้คุณสามารถเปลี่ยนชื่อของกลุ่มกล่อง / หน้าแท็บที่คล้ายกันได้อย่างง่ายดายในครั้งเดียว อีกแง่มุมหนึ่งคือคุณสามารถพิมพ์คลาสนั้นและมอบให้กับผู้ที่ไม่ใช่โปรแกรมเมอร์ซึ่งสามารถตรวจสอบคำอธิบายภาพว่าใช้งานง่ายหรือไม่และข้อความที่ส่งถึงผู้ใช้นั้นละเอียดเกินไปหรือสับสนเกินไป

อย่างไรก็ตามฉันเห็นข้อเสียบางอย่าง:

  • ทุกชั้นเรียนจะถูกผนวกเข้ากับชั้นเรียนอย่างต่อเนื่อง
  • การเพิ่ม / ลบ / เปลี่ยนชื่อ / ย้ายค่าคงที่ต้องมีการคอมไพล์ใหม่อย่างน้อย 90% ของแอปพลิเคชัน (หมายเหตุ: การเปลี่ยนค่าไม่ได้เป็นอย่างน้อยสำหรับ C ++) ในหนึ่งในโปรเจ็กต์ C ++ ของเราที่มีคลาส 1,500 คลาสซึ่งหมายถึงเวลาในการรวบรวมประมาณ 7 นาที (โดยใช้ส่วนหัวที่คอมไพล์แล้วโดยไม่มีเวลาประมาณ 50 นาที) และใช้เวลาเชื่อมโยงกับไลบรารีคงที่บางประมาณ 10 นาที
  • การสร้างการเพิ่มประสิทธิภาพความเร็วด้วย Visual Studio Compiler ใช้เวลาสูงสุด 3 ชั่วโมง ฉันไม่รู้ว่าความสัมพันธ์ในชั้นเรียนขนาดใหญ่เป็นแหล่งที่มาหรือไม่
  • คุณได้รับแรงผลักดันเข้าสู่สตริงการเข้ารหัสที่เข้ารหัสชั่วคราวยาก ๆ เพราะคุณต้องการทดสอบบางสิ่งอย่างรวดเร็วและไม่ต้องการที่จะรอ 15 นาทีสำหรับการทดสอบนั้น ทุกคนรู้ว่าเกิดอะไรขึ้นกับ "ฉันจะแก้ไขในภายหลัง" - ความคิด
  • การนำคลาสไปใช้ในโครงการอื่นนั้นไม่ใช่เรื่องง่ายเสมอไป (ส่วนใหญ่เป็นเพราะข้อต่อแน่นอื่น ๆ แต่ค่าคงที่การจัดการไม่ได้ทำให้ง่ายขึ้น)

คุณจะเก็บค่าคงที่แบบนั้นอยู่ที่ไหน นอกจากนี้คุณจะโต้แย้งอะไรเพื่อโน้มน้าวผู้จัดการโครงการของคุณว่ามีแนวคิดที่ดีกว่าซึ่งสอดคล้องกับข้อได้เปรียบที่ระบุไว้ข้างต้น

อย่าลังเลที่จะให้คำตอบ C ++ ที่เจาะจงหรือเป็นอิสระ

PS: ฉันรู้ว่าคำถามนี้เป็นเรื่องส่วนตัว แต่ฉันไม่รู้สถานที่ที่ดีไปกว่าเว็บไซต์นี้สำหรับคำถามประเภทนี้

อัพเดทโครงการนี้

ฉันมีข่าวเรื่องเวลารวบรวม:
จากการโพสต์ของ Caleb และ gbjbaanb ฉันแบ่งไฟล์ค่าคงที่ของฉันออกเป็นไฟล์อื่น ๆ หลายไฟล์เมื่อฉันมีเวลา ในที่สุดฉันก็แยกโครงการของฉันออกเป็นหลายห้องสมุดซึ่งตอนนี้เป็นไปได้ง่ายขึ้นมาก การคอมไพล์ในโหมดการวางจำหน่ายแสดงให้เห็นว่าไฟล์ที่สร้างขึ้นอัตโนมัติซึ่งมีคำจำกัดความของฐานข้อมูล (ตารางชื่อคอลัมน์และอื่น ๆ - มากกว่า 8000 สัญลักษณ์) และการสร้างแฮชบางอย่างทำให้เกิดการคอมไพล์ครั้งใหญ่ในโหมดการเปิดตัว

การปิดใช้งานเครื่องมือเพิ่มประสิทธิภาพ MSVC สำหรับไลบรารีที่มีค่าคงที่ฐานข้อมูลทำให้เราสามารถลดเวลาการรวบรวมทั้งหมดของโครงการของคุณ (หลายแอปพลิเคชั่น) ในโหมดการปล่อยจาก 8 ชั่วโมงเป็นน้อยกว่าหนึ่งชั่วโมง!

เรายังไม่ทราบว่าทำไม MSVC จึงมีความยากลำบากในการปรับไฟล์เหล่านี้ แต่ตอนนี้การเปลี่ยนแปลงนี้ช่วยลดแรงกดดันได้มากเนื่องจากเราไม่ต้องพึ่งพาการสร้างในตอนกลางคืนเท่านั้น

ความจริงนั้น - และประโยชน์อื่น ๆ เช่นข้อต่อที่แน่นน้อยกว่าการใช้ซ้ำได้ดีขึ้นเป็นต้น - ยังแสดงให้เห็นว่าการใช้เวลาแยก "ค่าคงที่" นั้นไม่ใช่ความคิดที่เลวร้ายหลังจากทั้งหมด ;-)

Update2

เนื่องจากคำถามนี้ยังคงได้รับความสนใจ:
นี่คือสิ่งที่ฉันได้ทำในไม่กี่ปีที่ผ่านมา:

ใส่ค่าคงที่ตัวแปรและอื่น ๆ ทั้งหมดลงในขอบเขตที่เกี่ยวข้อง: ถ้าคุณใช้ค่าคงที่เฉพาะในวิธีการเดียวมันก็โอเคที่จะกำหนดมันในวิธีการนั้น ถ้าคลาสเดียวสนใจให้ปล่อยให้มันเป็นรายละเอียดการใช้งานส่วนตัวของคลาสนั้น เช่นเดียวกับเนมสเปซโมดูลโครงการขอบเขตของ บริษัท ฉันยังใช้รูปแบบเดียวกันสำหรับฟังก์ชั่นตัวช่วยและชอบ (สิ่งนี้อาจใช้ไม่ได้ 100% ถ้าคุณพัฒนากรอบงานสาธารณะ)

การทำเช่นนี้สามารถนำมาใช้ใหม่ได้เพิ่มขึ้นทดสอบได้และบำรุงรักษาในระดับที่คุณไม่เพียง แต่ใช้เวลาน้อยลงในการรวบรวม (อย่างน้อยใน C ++) แต่ยังมีเวลาน้อยลงในการแก้ไขข้อผิดพลาดซึ่งทำให้คุณมีเวลามากขึ้น ในขณะเดียวกันการพัฒนาคุณสมบัติเหล่านี้จะทำงานได้เร็วขึ้นเนื่องจากคุณสามารถใช้รหัสได้ง่ายขึ้น สิ่งนี้มีความได้เปรียบมากกว่าไฟล์ค่าคงที่ส่วนกลางใด ๆ ที่อาจมีขนาด

ดูโดยเฉพาะอย่างยิ่งหลักการแยกส่วนต่อประสานและหลักการความรับผิดชอบเดี่ยวหากคุณต้องการทราบข้อมูลเพิ่มเติม

ถ้าคุณเห็นด้วยตอบคำถามของ Caleb ตั้งแต่อัปเดตนี้เป็นเรื่องทั่วไปที่เขาพูด


2
โดยส่วนตัวฉันจะไม่มีชื่อ UI หรือสตริงข้อความเป็นค่าคงที่เลย ฉันมีมันใน app.config
jk

1
ฉันชอบวิธีที่คุณทำตอนนี้ - ฉันเข้าใจข้อเสียของคุณ แต่เราอาจต้องจัดการกับมัน
bigtang

1
ฉันเคยเห็นปัญหาเดียวกันในโครงการ Java ขนาดใหญ่ ... อินเทอร์เฟซ "ค่าคงที่" ขนาดใหญ่หนึ่งอย่างเปลี่ยนสิ่งใด ๆ ในนั้นและรอ 15 นาทีเพื่อให้คราสทำการคอมไพล์ใหม่ ฉันอยู่กับ Caleb: จัดกลุ่มค่าคงที่ที่พวกเขาอยู่ตามธรรมชาติใกล้กับรหัสที่ใช้พวกเขา ทำให้พวกเขาแยกจากกันเพราะพวกมันยังอยู่ที่การออกกำลังกาย OCD ที่ไร้ประโยชน์
Michael Borgwardt

การมีเพศสัมพันธ์อย่างแน่นหนาไม่ใช่ปัญหาเพราะนั่นคือสิ่งที่คุณต้องการจริงๆ คุณต้องการให้การเปลี่ยนแปลงหนึ่งไฟล์ในค่าคงที่ของคุณส่งผลกระทบต่อไฟล์ต้นฉบับมากมาย (แน่นอนคุณมีปัญหาอื่น ๆ เช่นกัน)
gnasher729

@ gnasher729 ที่เป็นจริงถ้ามีหลายคลาสที่ใช้ค่าคงที่เดียวกัน คุณไม่ต้องการให้ชั้นเรียนควบคู่กับค่าคงที่ที่ไม่เกี่ยวข้อง มันอาจไม่เป็นปัญหาในตอนแรกจนกว่าคุณจะลองนำมาใช้ใหม่ในโครงการอื่นโดยไม่คัดลอกหรือรันการทดสอบแยก
Tim Meyer

คำตอบ:


29

ค่าคงที่ที่เฉพาะเจาะจงกับคลาสควรไปในอินเทอร์เฟซของคลาสนั้น

ค่าคงที่เป็นตัวเลือกการกำหนดค่าจริง ๆ ควรเป็นส่วนหนึ่งของคลาสการกำหนดค่า หากคุณให้ accessors สำหรับตัวเลือกการกำหนดค่าในชั้นเรียนนั้น (และใช้พวกมันแทนค่าคงที่ที่อื่น) คุณจะไม่ต้องคอมไพล์โลกทั้งใบเมื่อคุณเปลี่ยนตัวเลือกไม่กี่ตัว

ค่าคงที่ที่ใช้ร่วมกันระหว่างชั้นเรียน แต่ที่ไม่ได้ตั้งใจจะกำหนดค่าควรถูกกำหนดขอบเขตอย่างเหมาะสม - พยายามแบ่งออกเป็นไฟล์ที่มีการใช้งานเฉพาะเพื่อให้แต่ละชั้นเรียนรวมเฉพาะสิ่งที่พวกเขาต้องการจริงๆ สิ่งนี้จะช่วยลดเวลาในการคอมไพล์เมื่อคุณเปลี่ยนค่าคงที่เหล่านั้นบางส่วน


1
ในกรณีที่คุณมีความสนใจ: ฉันอัปเดตคำถามของฉันด้วยสิ่งที่ฉันได้ทำตามคำตอบของคุณและคนอื่น ๆ
ทิมเมเยอร์

6

ฉันจะบอกง่ายๆว่าคุณต้องการแยกชั้นค่าคงที่ขนาดใหญ่ของคุณออกเป็นไฟล์ขนาดเล็กจำนวนมากตัวอย่างเช่นต่อแบบฟอร์ม สิ่งนี้ทำให้แน่ใจได้ว่าคุณไม่มีการขึ้นต่อกันอย่างมากมายในไฟล์ค่าคงที่ดังนั้นการเพิ่มหรืออัพเดตสตริงจะไม่ต้องการการคอมไพล์ซ้ำทั้งหมด คุณยังสามารถเก็บไฟล์เหล่านี้ไว้ในตำแหน่งส่วนกลางได้ แต่ (เช่น) มี 1 ไฟล์ที่มีค่าคงที่สำหรับแต่ละกล่องโต้ตอบโดยตั้งชื่อตามความเหมาะสม จากนั้นคุณสามารถรวมไฟล์เหล่านั้นในไฟล์โต้ตอบที่เกี่ยวข้องเท่านั้นซึ่งจะลดการรวบรวมซ้ำอย่างหนาแน่น

ฉันขอแนะนำให้คุณใช้บางอย่างเช่นโปรแกรมอรรถประโยชน์ GetText ของ GNU เพื่อจัดการกับสตริงมันถูกออกแบบมาเพื่อการแปล แต่ใช้งานได้ดีสำหรับการเปลี่ยนข้อความเป็นอย่างอื่น คุณสามารถทำให้พวกเขาอยู่ในทรัพยากรของสาย แต่ฉันคิดว่าพวกเขาจะยากที่จะทำงานกับพวกเขาโดยพวกเขาเป็นรหัส ID, GetText utils จะถูก keyed โดยสายเดิม - ทำให้สิ่งที่ง่ายต่อการพัฒนา


ฉันอาจให้ช็อตนั้น เนื่องจากชั้นค่าคงที่ที่มีชื่อเรื่อง ฯลฯ ถูกแบ่งออกเป็นหลายโครงสร้างฉันอาจจะทำหนึ่งคลาสต่อโครงสร้างเป็นจุดเริ่มต้น ไม่แน่ใจเกี่ยวกับสิ่งที่ GNU เรามักจะไม่ต้องการเปลี่ยนสายของเราที่รันไทม์เพียงในช่วงเวลาการพัฒนา เราใช้กลไกการแปลของ Qt ในกรณีที่เราต้องแปลเป็นภาษาอื่นในอนาคต
Tim Meyer

ในกรณีที่คุณมีความสนใจ: ฉันอัปเดตคำถามของฉันด้วยสิ่งที่ฉันได้ทำตามคำตอบของคุณและคนอื่น ๆ
ทิมเมเยอร์

2

หมายเหตุ: ฉันไม่ใช่นักพัฒนา C ++ ... แต่นี่คือความคิดของฉัน: คุณต้องพิจารณาดังต่อไปนี้ความคิดเห็นของ @ jk เกี่ยวกับความแตกต่างระหว่างการใช้ไฟล์การกำหนดค่า ใน DotNet มีไฟล์ทรัพยากรที่ใช้ในการจัดเก็บข้อมูลดังกล่าว ใน Windows Forms ไฟล์ทรัพยากรจะถูกเก็บรักษาไว้จาก VS สำหรับแต่ละฟอร์ม

ฉันไม่เห็นค่าสำหรับค่าคงที่ที่จะอยู่นอกขอบเขตการใช้งานยกเว้นว่าเป็นค่าคงที่ทั่วโลกที่ต้องแชร์ ดังที่คุณกล่าวถึงสิ่งนี้จะเป็นเรื่องยากที่จะรักษาในระหว่างการพัฒนาอย่างน้อย นอกจากนี้คุณอาจได้รับชื่อองค์กร อีกสิ่งหนึ่งคือมันอาจเป็นเรื่องยากที่จะรู้ว่าใครกำลังใช้ค่าคงที่ที่กำหนด

ตอนนี้ถ้าคุณไม่ต้องการให้โปรแกรมเมอร์ตรวจสอบข้อมูลสำหรับ GUI คุณสามารถจับภาพหน้าจอได้ หากคุณต้องการให้พวกเขาตรวจสอบรายการตารางข้อมูลคุณสามารถส่งออกข้อมูลไปยัง Excel หรือสิ่งที่คล้ายกัน

หากคุณยังต้องการใช้วิธีการระบุตำแหน่งแบบรวมศูนย์และคุณต้องการให้ค่าคงที่ทั้งหมดของคุณอยู่ในไฟล์ขนาดใหญ่ไฟล์เดียวนักพัฒนาแต่ละคนอาจใช้ไฟล์ที่แชร์ซึ่งอัปเดตเมื่อสิ้นสุดแต่ละช่วงเวลาเป็นไฟล์กลาง ข้อมูลจะมาจากไฟล์ส่วนบุคคลที่ใช้ในการพัฒนา สิ่งนี้สามารถเป็นไปโดยอัตโนมัติหรือทำได้ด้วยตนเองอย่างง่ายดาย อย่างไรก็ตามอย่างที่ฉันบอกไปอาจเป็นความเสี่ยงที่คุณไม่ต้องทำ


2

ไม่มีวิธีแก้ปัญหาทั่วไป ถามตัวเองเกี่ยวกับประสิทธิภาพการใช้งานความปลอดภัยและวงจรชีวิตของค่าคงที่

ยิ่งพวกเขากำหนดขอบเขตของการทำงานให้ใกล้ยิ่งประสิทธิภาพจะยิ่งสูง

ยิ่งมีการจัดกลุ่มอย่างมีเหตุผลและอยู่นอกขอบเขตความสามารถในการนำกลับมาใช้จะสูงขึ้น

ค่าใช้จ่ายที่เข้าถึงได้น้อยคือความปลอดภัยที่สูงขึ้น

ยิ่งอายุการใช้งานของค่าคงที่สูงขึ้นเท่าใดค่าใช้จ่ายก็จะน้อยลงตามความเหมาะสมของคุณ

ค่าคงที่เช่นหมายเลขเวอร์ชันจะถูกกำหนดในรูปแบบรายการบางอย่าง รหัสข้อผิดพลาดของฟังก์ชั่นข้อผิดพลาดจะถูกกำหนดไว้ในชั้นเรียน รหัสข้อผิดพลาดน่าจะเป็นสิ่งที่มีอายุการใช้งานยาวนาน (= แทบไม่เคยเปลี่ยนแปลง) วางไว้ในไฟล์คงที่เพียงแค่ spams ไฟล์ด้วยสิ่งที่ไม่จำเป็น

ค่าคงที่ที่น้อยกว่าจะมีอักขระของค่าคงที่ แต่ตัวแปร (เช่นหมายเลขเวอร์ชัน) ยิ่งคุณสามารถวางไว้ด้านนอกมากขึ้น ตัวแปรที่น้อยกว่าค่าคงที่คือดังนั้นยิ่งมีค่าคงที่มากขึ้นเท่าไหร่มันก็ยิ่งควรอยู่ในขอบเขตของมันมากขึ้นเท่านั้น ในระหว่างการดีบั๊กมันเหมาะสมที่จะวางไว้ข้างนอกเพื่อลดเวลาในการรวบรวม

อย่างไรก็ตามปัญหาเริ่มต้นของคุณคือเวลารวบรวม ดังนั้นคำถามคือคุณถามคำถามที่ถูกต้องหรือไม่ หากเวลารวบรวมของแอปพลิเคชันของคุณสูงเกินไปคุณควรคิดถึงวิธีที่จะทำให้เป็นโมดุลมากขึ้นเพื่อให้ชิ้นส่วนทำงานได้อย่างอิสระจากกัน รวบรวมบางส่วนและทดสอบข้อมูลของคุณอย่างอิสระ หากการทดสอบหน่วยของคุณทำอย่างถูกต้องและเต็มรูปแบบ (ซึ่งเป็นงานจำนวนมากจริง ๆ ) จากนั้นคุณสามารถเลื่อนสิ่งต่าง ๆ ไปมาได้โดยไม่ต้องกังวล จากนั้นคำถามจะได้รับแรงผลักดันที่แตกต่างอย่างสิ้นเชิง


1

ฉันขอแนะนำให้ใส่ค่าคงที่เหล่านี้ทั้งหมดลงในไฟล์กำหนดค่าบางประเภท สำหรับแอปพลิเคชัน Java เรามักจะใช้ไฟล์. properties ข้อความแบบง่าย ๆ ที่มีการจัดรูปแบบแต่ละบรรทัดเป็น "(key) = (value)" ตัวอย่าง

MainPanel.Title = ยินดีต้อนรับสู่ใบสมัครของเรา
DB.table.users = TBL_USERS
logging.filename = application.log

จากนั้นคุณโหลดไฟล์นี้ตอนรันไทม์เติมแคชที่ให้คุณค้นหาคีย์และรับค่ากลับมา เมื่อคุณต้องการค่าคงที่คุณจะต้องค้นหาแคช คุณจะต้องมีคีย์ของคุณอยู่ที่ไหนสักแห่งและแคชจะต้องสามารถเข้าถึงได้ทั่วโลก แต่เมื่อคุณเปลี่ยนค่าจริงของค่าคงที่ไม่จำเป็นต้องทำการคอมไพล์ซ้ำคุณควรเปิดแอปใหม่ได้ (หรือหาก คุณต้องการรับแฟนซีมีไฟล์. properties และแคชจำนวนมากและให้แอปพลิเคชันสามารถโหลดแคชในเวลาทำงานได้)

สำหรับการดำเนินการฉันพบคำถาม SO นี้: https://stackoverflow.com/questions/874052/properties-file-library-for-c-or-c-มันเป็นครั้งแรกในการค้นหาของ Google - ฉันยังไม่ได้ ใช้ซอฟต์แวร์นี้จริง ๆ ด้วยตัวเอง)


สำหรับโครงการ C ++ เราจะต้องคอมไพล์ไฟล์ค่าคงที่อีกครั้งหากเราเปลี่ยนค่า นี่เป็นเพราะค่าถูกกำหนดในไฟล์. cpp อย่างไรก็ตามการเพิ่ม / ลบ / เปลี่ยนชื่อ / ย้ายค่าคงที่ยังคงต้องมีการสร้างใหม่เต็มรูปแบบ
Tim Meyer

@TimMeyer: หากคุณแยกค่าคงที่เป็นหลายไฟล์การเพิ่ม / ลบค่าคงที่จะส่งผลเฉพาะไฟล์ที่ขึ้นอยู่กับไฟล์นั้น ๆ ถูกต้องหรือไม่
FrustratedWithFormsDesigner

แก้ไข. ปัญหาหลักคือว่าถ้าผมชี้ให้เห็นว่าผู้คนมักจะพูดถึงหนึ่งในสิ่งที่ฉันแสดงเป็น "ข้อดี" ได้หายไป
ทิมเมเยอร์

อย่างไรก็ตามฉันไม่ได้คิดเกี่ยวกับการวางไฟล์ค่าคงที่หลายไฟล์ไว้ในที่เดียวกัน
Tim Meyer

+1 @Tim Meyer: เพื่อจุดประสงค์นี้การตรวจสอบเวลาแบบคอมไพล์มีค่ามากกว่าที่จะประหยัด นอกจากนี้คุณจะทำอย่างไรถ้าคุณต้องการทำให้เป็นสากล?
kevin cline
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.