การออกแบบ OOP ที่ไม่ดีสำหรับการจำลองที่เกี่ยวข้องกับอินเตอร์เฟสหรือไม่


13

ฉันกำลังออกแบบโปรแกรม OOP ตัวเล็ก ๆ ของฉันเพื่อจำลอง Vampires, Wolves, Human และ Trucks และกำลังพยายามใช้ความเข้าใจที่ จำกัด ของตัวเองเกี่ยวกับการเชื่อมต่อ

( ฉันยังคงสรุปอยู่ที่นี่และยังไม่มีการติดตั้งโค้ดดังนั้นจึงเป็นคำถามของการออกแบบ OOP ... ฉันคิดว่า!)

ฉันกำลังมองหา'พฤติกรรมทั่วไป'ระหว่างชั้นเรียนเหล่านี้และนำไปใช้เป็นส่วนต่อประสานหรือไม่

ตัวอย่างเช่น Vampires and Wolves กัด ... ดังนั้นฉันควรมีส่วนต่อประสานกัดหรือไม่

public class Vampire : Villain, IBite, IMove, IAttack

เช่นเดียวกันสำหรับรถบรรทุก ...

public class Truck : Vehicle, IMove

และสำหรับมนุษย์ ...

public class Man : Human, IMove, IDead

ความคิดของฉันอยู่ที่นี่ใช่ไหม (ขอบคุณที่คุณช่วย)


14
สัตว์ผักและแร่ธาตุเป็นตัวอย่างที่ดีสำหรับการนำไปใช้งาน การใช้งานที่เกิดขึ้นจริงโดยทั่วไปมักจะเป็นนามธรรมมากขึ้นเช่นIEnumerable, IEquatableฯลฯ
โรเบิร์ตฮาร์วีย์

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

@tofro ความตั้งใจของฉันคือ IBite จะมีหลายวิธีที่จะใช้พฤติกรรมที่เกี่ยวข้องกับ (1) การลดระดับ 'ชีวิต / พลังงาน' ของผู้อื่น (2) การปรากฏตัวหรือการเรียกใช้กราฟิก 'เลือด' และ (3) การปรับปรุงสถิติจำลอง ข้อมูล (เช่น NoOfBites) ฉันคิดว่าฉันซาบซึ้งที่ส่วนต่อประสานนั้นใช้ดีที่สุดในการปรับใช้วิธีการต่างๆ
user3396486

2
อย่าคลาส Human, Vampire และ Vehicle ใช้อินเทอร์เฟซ IMove แล้วหรือยัง เหตุใดคุณต้องทำให้คลาสย่อยใช้งานอย่างละเอียดเกินไป
Pierre Arlaud

อินเตอร์เฟสทั้งหมดนี้จำเป็นจริงๆหรือ? ใน Python โชคดีที่คุณไม่ต้องการอะไรเลย ehich เป็นการเปลี่ยนแปลงที่สดชื่นจริงๆ (ภาษาแรกของฉันคือ Object Pascal) วิธีเสมือนอาจเป็นวิธีแก้ปัญหาที่ดีกว่าในบางกรณี
Ajasja

คำตอบ:


33

โดยทั่วไปคุณต้องการมีอินเตอร์เฟสสำหรับคุณลักษณะทั่วไปของ clasess ของคุณ

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

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

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

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


1
แน่นอนฉันหวังว่าแต่ละวัตถุที่ไม่ได้มีมากมายของคุณลักษณะ
Gardenhead

4
แอททริบิวไม่ได้อยู่ในแอตทริบิวต์ oop แต่มีคุณลักษณะ / คุณสมบัติไวยากรณ์ (สิ่งต่าง ๆ เช่นนับจำนวนเปรียบเทียบได้ ฯลฯ ): D ทางเลือกที่ไม่ดีของคำ
Paul92

3
เป็นที่น่าสังเกตว่าอินเทอร์เฟซที่มีประโยชน์เป็นสิ่งที่คุณจะใช้ ตัวอย่างเช่นIBiteไม่มีประโยชน์โดยเฉพาะอย่างยิ่ง แต่คุณอาจต้องการIAttackเพื่อให้คุณสามารถทำงานกับทุกสิ่งที่ทำให้เกิดการโจมตีหรือIUpdateเพื่อให้คุณสามารถเรียกใช้การปรับปรุงสำหรับทุกสิ่งหรือIPhysicsEnabledเพื่อให้คุณสามารถใช้ฟิสิกส์กับพวกเขา ฯลฯ
anaximander

1
คำตอบนี้ทำให้ได้คะแนนที่ดีมาก ย่อหน้าสุดท้ายสรุปมันออกมาค่อนข้างดี อย่างน้อยเช่นเดียวกับที่คุณสามารถทำได้กับระดับของรายละเอียดที่ให้ไว้
การแข่งขัน Lightness ใน Orbit

1
วิธีการจัดกลุ่มคอมมอนส์เหมาะกับคลาสนามธรรมมากขึ้น อินเทอร์เฟซถูกสร้างขึ้นมาเพื่อออกแบบสัญญาที่ต้องเคารพผู้ที่ใช้มัน
Walfrat

29

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

ถ้าฉันมีCombatคลาสที่มีfight()เมธอดเมธอดนั้นน่าจะมีความต้องการที่จะเรียกทั้งคู่move()และattack()บนวัตถุเดียวกัน นั่นแสดงให้เห็นถึงความต้องการICombatantอินเทอร์เฟซที่fight()สามารถโทรmove()และattack()ผ่านได้อย่างมาก สิ่งนี้สะอาดกว่าfight()การหยิบIAttackวัตถุและใช้IMoveเพื่อดูว่ามันสามารถเคลื่อนที่ได้หรือไม่

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

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


1
ประณามสิ่งนี้ดี การเล่นเกมดูเหมือนเป็นวิธีที่ดีในการใช้และอธิบาย OOP
JeffO

7
@JeffO จนกว่าคุณจะสร้างเกมที่มีขนาดใหญ่พอสมควรและตระหนักว่า OOP นั้นเป็นเกมที่ร้อนแรงและคุณจะดีขึ้นเมื่อใช้ระบบที่อิงกับองค์ประกอบหรือการออกแบบที่เน้นข้อมูล
Darkhogg

"อินเทอร์เฟซเป็นของลูกค้าที่ใช้งานพวกเขา"
Tibos

4

1
+1 สำหรับความแตกต่างระหว่างไลบรารี่และแอปพลิเคชันฉันมักจะ (มากเกินไป?: /) อ่านสิ่งต่าง ๆ ที่เหมาะกับสิ่งหนึ่งและอื่น ๆ
Walfrat

3

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

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

int total = 0;
foreach (object it in creatures)
{
   IWoozleCountable w = trycast(it, IWoozleCountable);
   if (w != null) total += w.WoozleCount;
}

อย่างไรก็ตามหาก WoozleCount เป็นสมาชิกของ Creature / ICreature แม้ว่าจะมีชนิดย่อยเพียงเล็กน้อยที่จะแทนที่การใช้งาน WoozleCount ที่เป็นค่าเริ่มต้นของ Creature ที่จะส่งกลับค่าเป็นศูนย์เสมอ

int total = 0;
foreach (ICreature it in creatures)
   total += it.WoozleCount;

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

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