enums สร้างส่วนต่อประสานที่บอบบางหรือไม่?


17

ลองพิจารณาตัวอย่างด้านล่าง การเปลี่ยนแปลงใด ๆ กับ ColorChoice enum จะส่งผลกระทบต่อคลาสย่อย IWindowColor ทั้งหมด

enums มีแนวโน้มที่จะทำให้เกิดการเชื่อมต่อที่เปราะหรือไม่? มีอะไรดีไปกว่า Enum ที่จะยอมให้มีความยืดหยุ่นแบบ polymorphic มากขึ้นหรือไม่?

enum class ColorChoice
{
    Blue = 0,
    Red = 1
};

class IWindowColor
{
public:
    ColorChoice getColor() const=0;
    void setColor( const ColorChoice value )=0;
};

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

enum class CharacterType
{
    orc = 0,
    elf = 1
};

class ISomethingThatNeedsToKnowWhatTypeOfCharacter
{
public:
    CharacterType getCharacterType() const;
    void setCharacterType( const CharacterType value );
};

นอกจากนี้ให้จินตนาการว่าจัดการกับ ISomethingThatNeedsToKnowWhatTypeOfCharacter ที่เหมาะสมได้รับการเสนอในรูปแบบการออกแบบจากโรงงาน ตอนนี้ฉันมี API ที่ไม่สามารถขยายได้ในอนาคตสำหรับแอปพลิเคชันอื่นซึ่งประเภทอักขระที่อนุญาตคือ {human, dwarf}

แก้ไข: เพื่อเป็นรูปธรรมมากขึ้นเกี่ยวกับสิ่งที่ฉันกำลังทำงานอยู่ ฉันกำลังออกแบบการเชื่อมโยงข้อมูลจำเพาะ( MusicXML ) ที่รัดกุมและฉันใช้คลาส enum เพื่อแสดงชนิดเหล่านั้นในข้อมูลจำเพาะที่ประกาศด้วย xs: การแจงนับ ฉันพยายามคิดว่าจะเกิดอะไรขึ้นเมื่อเวอร์ชั่นถัดไป (4.0) ออกมา ไลบรารีคลาสของฉันสามารถทำงานในโหมด 3.0 และโหมด 4.0 ได้หรือไม่ หากรุ่นถัดไปรองรับ 100% แบบย้อนหลังอาจเป็นไปได้ แต่ถ้าค่าการแจงนับถูกลบออกจากข้อกำหนดแล้วฉันตายในน้ำ


2
เมื่อคุณพูดว่า "ความยืดหยุ่นแบบ polymorphic" คุณมีความสามารถอะไรในใจ?
Ixrec


3
การใช้ enum สำหรับสีจะสร้างอินเทอร์เฟซที่เปราะไม่เพียง แต่ใช้
Doc Brown

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

1
Re MusicXML: หากไม่มีวิธีง่ายๆในการบอกจากไฟล์ XML ที่แต่ละเวอร์ชันของ schema ใช้อยู่นั่นจะทำให้ฉันเป็นข้อบกพร่องในการออกแบบที่สำคัญในข้อกำหนด หากคุณต้องแก้ปัญหาอย่างใดอาจไม่มีวิธีที่เราจะช่วยจนกว่าเราจะรู้ว่าสิ่งที่พวกเขาจะเลือกที่จะทำลายใน 4.0 และคุณสามารถถามเกี่ยวกับปัญหาเฉพาะที่ทำให้เกิด
Ixrec

คำตอบ:


25

เมื่อใช้อย่างถูกต้องแล้ว enums นั้นสามารถอ่านได้และแข็งแกร่งกว่า "เลขเวท" ที่พวกมันใช้แทน ปกติฉันไม่เห็นพวกเขาทำรหัสเปราะมากขึ้น ตัวอย่างเช่น

  • setColor () ไม่ต้องเสียเวลาตรวจสอบว่าvalueเป็นค่าสีที่ถูกต้องหรือไม่ คอมไพเลอร์ได้ทำเช่นนั้นแล้ว
  • คุณสามารถเขียน setColor (Color :: Red) แทน setColor (0) ฉันเชื่อว่าenum classคุณลักษณะใน C ++ ที่ทันสมัยช่วยให้คุณบังคับให้ผู้คนเขียนแบบเดิมแทนที่จะเป็นแบบหลัง
  • โดยทั่วไปแล้วจะไม่สำคัญ แต่ enums ส่วนใหญ่สามารถนำไปใช้กับประเภทใดก็ได้ขนาดหนึ่งดังนั้นผู้รวบรวมสามารถเลือกขนาดใดก็ได้ที่สะดวกที่สุดโดยไม่บังคับให้คุณคิดเกี่ยวกับสิ่งต่าง ๆ

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

ฉันไม่แน่ใจว่าคำถาม "polymorphic elastic" ของคุณคืออะไร Enums ไม่มีรหัสที่ปฏิบัติการได้ดังนั้นจึงไม่มีอะไรที่จะทำให้ polymorphic บางทีคุณกำลังมองหารูปแบบคำสั่ง ?

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


ฉันจะหาข้อมูลเพิ่มเติมเกี่ยวกับการไม่อนุญาตให้ 0 ส่งผ่านเป็น enum ได้อย่างไร
TankorSmash

5
@TankorSmash C ++ 11 แนะนำ "enum class" หรือที่เรียกว่า "scums enums" ซึ่งไม่สามารถแปลงเป็นประเภทตัวเลขพื้นฐานได้ พวกเขายังหลีกเลี่ยงการทำให้เนมสเปซสกปรกเหมือนประเภท "enum" ประเภท C แบบเก่า
Matthew James Briggs

2
Enums มักจะถูกสำรองข้อมูลด้วยจำนวนเต็ม มีสิ่งแปลก ๆ มากมายที่สามารถเกิดขึ้นได้ในการทำให้เป็นอนุกรม / ดีซีเรียลไลซ์เซชั่นหรือการคัดเลือกระหว่างจำนวนเต็มกับ enums ไม่ปลอดภัยเสมอไปที่จะสันนิษฐานว่า enum จะมีค่าที่ถูกต้องเสมอ
เอริค

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

1
@Ixrec "เพราะในหลาย ๆ สถานการณ์ (ส่วนใหญ่?) ไม่มีเหตุผลที่จะ จำกัด ผู้ใช้ให้มีชุดสีเล็ก ๆ " มีกรณีที่ถูกกฎหมาย . Net Console จำลองคอนโซล windows แบบเก่าซึ่งสามารถมีข้อความในหนึ่งใน 16 สี (16 สีของมาตรฐาน CGA) msdn.microsoft.com/en-us/library/…
Pharap

15

การเปลี่ยนแปลงใด ๆ กับ ColorChoice enum จะส่งผลกระทบต่อคลาสย่อย IWindowColor ทั้งหมด

ไม่มันไม่ มีสองกรณี: ตัวดำเนินการอย่างใดอย่างหนึ่ง

  • จัดเก็บส่งคืนและส่งต่อค่า enum ไม่ดำเนินการกับพวกเขาในกรณีที่พวกเขาไม่ได้รับผลกระทบจากการเปลี่ยนแปลงใน enum หรือ

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

หากคุณใส่ "Sphere", "Rectangle" และ "Pyramid" ใน enum "Shape" และส่ง Enum ดังกล่าวไปที่ drawSolid()ฟังก์ชั่นที่คุณเขียนเพื่อวาดของแข็งที่สอดคล้องกันแล้วเช้าวันหนึ่งคุณตัดสินใจที่จะเพิ่ม " Ikositetrahedron "ค่าให้กับ enum คุณไม่สามารถคาดหวังว่าdrawSolid()ฟังก์ชั่นจะไม่ได้รับผลกระทบ หากคุณคาดหวังว่าจะวาดไอโซโทปฮีดตรอนโดยที่คุณไม่ต้องเขียนโค้ดจริงเพื่อวาดไอโซโทปฮีดตรอนนั่นเป็นความผิดของคุณไม่ใช่ความผิดของ enum ดังนั้น:

enums มีแนวโน้มที่จะทำให้เกิดการเชื่อมต่อที่เปราะหรือไม่?

ไม่พวกเขาทำไม่ได้ สิ่งที่ทำให้อินเตอร์เฟซที่เปราะคือโปรแกรมเมอร์คิดว่าตัวเองเป็นนินจาพยายามรวบรวมรหัสของพวกเขาโดยไม่เปิดใช้งานคำเตือนเพียงพอ จากนั้นคอมไพเลอร์ไม่เตือนพวกเขาว่าdrawSolid()ฟังก์ชั่นของพวกเขามีswitchคำสั่งที่ขาดcaseประโยคสำหรับค่า enum "Ikositetrahedron" ที่เพิ่งเพิ่มเข้ามาใหม่

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


ตอนนี้มีการบอกความจริง enums ไม่ใช่โครงสร้างเชิงวัตถุ พวกเขาเป็นมากกว่าการประนีประนอมในทางปฏิบัติระหว่างกระบวนทัศน์เชิงวัตถุและกระบวนทัศน์การเขียนโปรแกรมที่มีโครงสร้าง

วิธีการเชิงวัตถุล้วนๆในการทำสิ่งต่าง ๆ นั้นไม่ได้มีอยู่ แต่อย่างใดและแทนที่จะมีวัตถุอยู่ตลอดทาง

ดังนั้นวิธีการเชิงวัตถุที่จะใช้ตัวอย่างกับของแข็งล้วนเป็นวิธีที่ใช้ polymorphism: แทนที่จะมีวิธีการรวมศูนย์ที่ยิ่งใหญ่ซึ่งรู้วิธีวาดทุกอย่างและต้องบอกว่าของแข็งจะวาดคุณต้องประกาศ " คลาส "Solid" ด้วยวิธี abstract (pure virtual) draw()และจากนั้นคุณเพิ่มคลาสย่อย "Sphere", "Rectangle" และ "Pyramid" แต่ละตัวมีการใช้งานของตัวเองdraw()ซึ่งรู้วิธีวาดตัวเอง

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


มีคำแนะนำใด ๆ ในการทิ้งคำเตือนเวลารวบรวมสำหรับสวิตช์เหล่านั้น ฉันมักจะโยนข้อยกเว้นรันไทม์; แต่เวลารวบรวมอาจจะดี! ไม่ค่อยดีเท่าไร .. แต่การทดสอบหน่วยเป็นเรื่องสำคัญ
Vaughan Hilts

1
เป็นเวลานานแล้วที่ฉันใช้ C ++ ครั้งล่าสุดดังนั้นฉันไม่แน่ใจ แต่ฉันคาดว่าการจัดหาพารามิเตอร์ -Wall ให้กับคอมไพเลอร์และการละเว้นส่วนdefault:คำสั่งควรทำ การค้นหาอย่างรวดเร็วเกี่ยวกับเรื่องไม่ได้ให้ผลลัพธ์ที่ชัดเจนมากขึ้นดังนั้นสิ่งนี้อาจเหมาะสมกับหัวเรื่องของprogrammers SEคำถามอื่น
Mike Nakis

ใน C ++ สามารถตรวจสอบเวลาคอมไพล์ได้หากคุณเปิดใช้งาน ใน C # การตรวจสอบใด ๆ จะต้องเป็นเวลาทำงาน เมื่อใดก็ตามที่ฉันใช้ enum ที่ไม่ได้ตั้งค่าสถานะเป็นพารามิเตอร์ฉันต้องตรวจสอบความถูกต้องด้วย Enum.IsDefined แต่นั่นก็หมายความว่าคุณต้องอัปเดตการใช้ enum ทั้งหมดด้วยตนเองเมื่อคุณเพิ่มค่าใหม่ ดู: stackoverflow.com/questions/12531132/…
Mike รองรับโมนิก้า

1
ฉันหวังว่าโปรแกรมเมอร์เชิงวัตถุจะไม่ทำให้วัตถุการถ่ายโอนข้อมูลของพวกเขาเหมือนPyramidจริงรู้วิธีdraw()การปิรามิด อย่างดีที่สุดอาจมาจากSolidและมีGetTriangles()วิธีการและคุณสามารถส่งต่อไปยังSolidDrawerบริการ ฉันคิดว่าเรากำลังหลีกหนีจากตัวอย่างของวัตถุทางกายภาพเป็นตัวอย่างของวัตถุใน OOP
Scott Whitlock

1
ไม่เป็นไรไม่ชอบให้ใครทุบตีการเขียนโปรแกรมเชิงวัตถุตัวเก่าที่ดี :) โดยเฉพาะอย่างยิ่งเนื่องจากพวกเราส่วนใหญ่รวมการเขียนโปรแกรมที่ใช้งานได้และ OOP มากกว่า OOP ที่เข้มงวดอีกต่อไป
Scott Whitlock

14

Enums ไม่ได้สร้างอินเตอร์เฟซที่เปราะ ในทางที่ผิดของ enums ไม่

enums มีไว้เพื่ออะไร?

Enums ถูกออกแบบมาเพื่อใช้เป็นชุดของค่าคงที่ที่มีความหมาย พวกเขาจะใช้เมื่อ:

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

การใช้งาน enums ดี:

  • วันในสัปดาห์: (ตาม. สุทธิSystem.DayOfWeek) เว้นแต่คุณจะจัดการกับปฏิทินที่ไม่ชัดเจนอย่างไม่น่าเชื่อบางอย่างจะมีเพียง 7 วันต่อสัปดาห์
  • สีที่ไม่สามารถขยายได้: (ตาม. Net's System.ConsoleColor) บางสีอาจไม่เห็นด้วยกับสิ่งนี้ แต่. Net เลือกที่จะทำสิ่งนี้ด้วยเหตุผล ในระบบคอนโซลของ. Net มีเพียง 16 สีให้เลือกโดยคอนโซล 16 สีเหล่านี้สอดคล้องกับจานสีดั้งเดิมที่รู้จักกันในชื่อCGA หรือ 'Color Graphics Adapter''สีกราฟิกอะแดปเตอร์' จะไม่มีการเพิ่มค่าใหม่ซึ่งหมายความว่านี่เป็นการประยุกต์ใช้ enum ที่สมเหตุสมผล
  • Enumerations ที่เป็นตัวแทนของสถานะคงที่: (ตาม Java's Thread.State) ผู้ออกแบบของ Java ตัดสินใจว่าในรูปแบบการทำเกลียวของ Java จะมีชุดของสถานะคงที่ที่ Threadสามารถอยู่ในและเพื่อทำให้เรื่องต่าง ๆ ง่ายขึ้นสถานะที่แตกต่างกันเหล่านี้ . ซึ่งหมายความว่าการตรวจสอบตามสถานะจำนวนมากนั้นง่ายต่อการตรวจสอบและสวิตช์ที่ใช้งานจริงในค่าจำนวนเต็มโดยที่โปรแกรมเมอร์ไม่ต้องกังวลเกี่ยวกับค่าที่แท้จริง
  • Bitflags แสดงถึงตัวเลือกที่ไม่เกิดร่วมกัน: (ตาม. สุทธิSystem.Text.RegularExpressions.RegexOptions) Bitflags เป็นการใช้งานทั่วไปของ enums โดยทั่วไปแล้วในความจริงแล้วใน. Net enums ทั้งหมดมีHasFlag(Enum flag)วิธีการที่สร้างขึ้นพวกเขายังสนับสนุนผู้ประกอบการระดับบิตและมีการFlagsAttributeทำเครื่องหมาย enum ว่าตั้งใจที่จะใช้เป็นชุดของธง ด้วยการใช้ enum เป็นชุดของแฟล็กคุณสามารถแสดงกลุ่มของค่าบูลีนในค่าเดียวรวมถึงการตั้งค่าสถานะให้ชัดเจนเพื่อความสะดวก นี่จะเป็นประโยชน์อย่างยิ่งสำหรับการแทนค่าสถานะของการลงทะเบียนสถานะในโปรแกรมจำลองหรือสำหรับการแสดงสิทธิ์ของไฟล์ (อ่านเขียนดำเนินการ) หรือเกี่ยวกับสถานการณ์ใด ๆ ที่ชุดตัวเลือกที่เกี่ยวข้องไม่ได้เกิดขึ้นพร้อมกัน

การใช้ enums ไม่ถูกต้อง:

  • คลาส / ประเภทของตัวละครในเกม:ยกเว้นว่าเกมเป็นตัวอย่างหนึ่งนัดที่คุณไม่น่าจะใช้อีกครั้ง enums ไม่ควรใช้สำหรับคลาสของตัวละครเพราะโอกาสที่คุณจะต้องการเพิ่มคลาสมากขึ้น มันจะดีกว่าถ้ามีคลาสเดียวที่แสดงถึงตัวละครและมีตัวละครในเกมเป็น 'type' ที่แสดงเป็นอย่างอื่น วิธีหนึ่งในการจัดการสิ่งนี้คือรูปแบบTypeObjectโซลูชันอื่น ๆ รวมถึงการลงทะเบียนประเภทอักขระด้วยการลงทะเบียนพจนานุกรม / ประเภทหรือการผสมผสานของทั้งสอง
  • สีที่ขยายได้:หากคุณใช้ enum สำหรับสีที่อาจถูกเพิ่มไว้ในภายหลังไม่ใช่ความคิดที่ดีที่จะแสดงสิ่งนี้ในรูปแบบ enum มิฉะนั้นคุณจะถูกเพิ่มตลอดไป สิ่งนี้คล้ายกับปัญหาข้างต้นจึงควรใช้วิธีแก้ปัญหาที่คล้ายกัน (เช่นรูปแบบของ TypeObject)
  • Extensible state:หากคุณมีเครื่องสถานะที่อาจแนะนำรัฐอื่น ๆ อีกมากมายคุณไม่ควรแสดงสถานะเหล่านี้ผ่านการแจกแจง วิธีที่ต้องการคือการกำหนดอินเทอร์เฟซสำหรับสถานะของเครื่องจัดเตรียมการนำไปใช้งานหรือคลาสที่ล้อมอินเทอร์เฟซและมอบหมายการเรียกใช้เมธอด (คล้ายกับ รูปแบบกลยุทธ์ ) จากนั้นเปลี่ยนสถานะของมันด้วยการเปลี่ยนแปลง
  • Bitflags ที่แสดงถึงตัวเลือกที่ไม่เกิดร่วมกัน:หากคุณใช้ enums เพื่อเป็นตัวแทนของธงและสองสถานะนั้นไม่ควรเกิดขึ้นพร้อมกันคุณจะต้องยิงด้วยตัวเอง สิ่งใดก็ตามที่ถูกตั้งโปรแกรมให้ตอบสนองต่อธงใดธงหนึ่งในทันทีจะตอบสนองต่อธงใดก็ตามที่ถูกตั้งโปรแกรมให้ตอบกลับก่อนหรือแย่กว่านั้นก็อาจตอบสนองต่อทั้งสองอย่าง สถานการณ์แบบนี้เพิ่งจะถามถึงปัญหา วิธีที่ดีที่สุดคือการปฏิบัติต่อการไม่มีธงเป็นเงื่อนไขทางเลือกถ้าเป็นไปได้ (เช่นการไม่มีTrueธงหมายถึงFalse) พฤติกรรมนี้สามารถได้รับการสนับสนุนเพิ่มเติมผ่านการใช้ฟังก์ชันพิเศษ (เช่นIsTrue(flags)และIsFalse(flags))

ฉันจะเพิ่มตัวอย่าง bitflag ถ้าใครสามารถหาตัวอย่างการทำงานหรือรู้จัก enums ที่ใช้เป็น bitflags ฉันรู้ว่ามันมีอยู่ แต่น่าเสียดายที่ฉันจำไม่ได้ในตอนนี้
Pharap


@BLSully เป็นตัวอย่างที่ยอดเยี่ยม ไม่สามารถพูดได้ว่าฉันเคยใช้มาแล้วแต่มีเหตุผล
Pharap

4

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

ปัญหาคือเมื่อคุณมีฟังก์ชั่นที่สำคัญที่เกี่ยวข้องกับ enum นั่นคือคุณมีรหัสประเภทนี้วางอยู่รอบ ๆ :

switch (my_enum) {
case orc: growl(); break;
case elf: sing(); break;
...
}

หนึ่งหรือสองอันนี้ก็โอเค แต่ทันทีที่คุณมีค่า Enum ที่มีความหมายเช่นนี้switchข้อความเหล่านี้มีแนวโน้มที่จะทวีคูณเหมือน Tribbles ตอนนี้ทุกครั้งที่คุณขยาย enum คุณต้องตามล่าswitches ทั้งหมดที่เกี่ยวข้องเพื่อให้แน่ใจว่าคุณได้ครอบคลุมทุกอย่าง นี่เปราะ แหล่งข้อมูลเช่นรหัสสะอาดจะแนะนำให้คุณควรมีอย่างน้อยหนึ่งswitchค่าต่อ enum

สิ่งที่คุณควรทำแทนในกรณีนี้คือใช้หลักการ OO และสร้างส่วนต่อประสานสำหรับประเภทนี้ คุณอาจยังคง enum สำหรับการสื่อสารประเภทนี้ แต่ทันทีที่คุณต้องทำอะไรกับมันคุณสร้างวัตถุที่เกี่ยวข้องกับ enum อาจใช้ Factory การบำรุงรักษานี้ทำได้ง่ายกว่ามากเนื่องจากคุณเพียงแค่มองหาสถานที่สำหรับอัปเดตเดียว: โรงงานของคุณและโดยการเพิ่มคลาสใหม่


1

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

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

  2. อย่าทำเลขคณิตกับพวกเขา โดยเฉพาะอย่าทำการเปรียบเทียบคำสั่งซื้อ ทำไม? เพราะเมื่อนั้นคุณอาจประสบกับสถานการณ์ที่คุณไม่สามารถรักษาคุณค่าที่มีอยู่และรักษาความสงบเรียบร้อยไว้ได้ในเวลาเดียวกัน ยกตัวอย่างเช่น enum สำหรับทิศทางเข็มทิศ: N = 0, NE = 1, E = 2, SE = 3, …ตอนนี้ถ้าหลังจากการอัพเดทบางอย่างคุณรวม NNE และระหว่างทิศทางที่มีอยู่คุณสามารถเพิ่มพวกมันไปยังจุดสิ้นสุดได้ ของรายการและทำให้การเรียงลำดับหยุดชะงักหรือคุณสอดแทรกคีย์ที่มีอยู่และทำให้การแมปที่กำหนดไว้ใช้ในรหัสดั้งเดิม หรือคุณเลิกใช้คีย์เก่าทั้งหมดและมีชุดคีย์ใหม่ทั้งหมดพร้อมกับรหัสความเข้ากันได้บางอย่างซึ่งแปลระหว่างคีย์เก่าและใหม่เพื่อประโยชน์ของรหัสดั้งเดิม

  3. เลือกขนาดที่เพียงพอ โดยค่าเริ่มต้นคอมไพเลอร์จะใช้จำนวนเต็มที่น้อยที่สุดที่สามารถมีค่า enum ทั้งหมด ซึ่งหมายความว่าหากในการอัปเดตชุด enums ที่เป็นไปได้ของคุณขยายจาก 254 ถึง 259 คุณก็ต้องมี 2 ไบต์สำหรับทุกค่า enum แทนที่จะเป็นหนึ่ง สิ่งนี้อาจทำลายโครงสร้างและเลย์เอาต์ของคลาสไปทั่วสถานที่ดังนั้นพยายามหลีกเลี่ยงสิ่งนี้โดยใช้ขนาดที่เพียงพอในการออกแบบครั้งแรก C ++ 11 ให้คุณควบคุมได้มากมายที่นี่ แต่การระบุรายการLAST_SPECIES_VALUE=65535ควรช่วยได้เช่นกัน

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

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

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