ในบทความบล็อกชุดนี้ Eric Lippert อธิบายถึงปัญหาในการออกแบบเชิงวัตถุโดยใช้พ่อมดและนักรบเป็นตัวอย่างโดยที่:
abstract class Weapon { }
sealed class Staff : Weapon { }
sealed class Sword : Weapon { }
abstract class Player
{
public Weapon Weapon { get; set; }
}
sealed class Wizard : Player { }
sealed class Warrior : Player { }
แล้วเพิ่มกฎสองสามข้อ:
- นักรบสามารถใช้ดาบได้เท่านั้น
- ตัวช่วยสร้างสามารถใช้พนักงานได้เท่านั้น
จากนั้นเขาก็จะแสดงให้เห็นถึงปัญหาที่คุณพบหากคุณพยายามบังคับใช้กฎเหล่านี้โดยใช้ระบบประเภท C # (เช่นทำให้Wizardชั้นเรียนมีความรับผิดชอบในการทำให้แน่ใจว่าตัวช่วยสร้างสามารถใช้พนักงานได้เท่านั้น) คุณละเมิดหลักการทดแทน Liskov, ความเสี่ยงข้อยกเว้นรันไทม์หรือจบลงด้วยรหัสที่ยากต่อการขยาย
วิธีแก้ปัญหาที่เขาเกิดขึ้นคือไม่มีการตรวจสอบความถูกต้องโดยคลาสผู้เล่น มันใช้เพื่อติดตามสถานะเท่านั้น จากนั้นแทนที่จะให้อาวุธแก่ผู้เล่นโดย:
player.Weapon = new Sword();
สถานะถูกแก้ไขโดยCommands และตามRules:
... เราทำให้
Commandวัตถุที่เรียกWieldว่าใช้เวลาสองวัตถุเกมรัฐเป็นและPlayerWeaponเมื่อผู้ใช้ออกคำสั่งไปยังระบบ“ ตัวช่วยสร้างนี้ควรควงดาบนั้น” จากนั้นคำสั่งนั้นจะถูกประเมินในบริบทของชุดของRules ซึ่งสร้างลำดับของEffects เรามีสิ่งหนึ่งRuleที่บอกว่าเมื่อผู้เล่นพยายามควงอาวุธผลที่ได้คืออาวุธที่มีอยู่หากมีหนึ่งถูกทิ้งและอาวุธใหม่กลายเป็นอาวุธของผู้เล่น เรามีกฎอีกข้อหนึ่งที่เสริมความแข็งแกร่งให้กับกฎข้อแรกซึ่งระบุว่าเอฟเฟกต์ของกฎข้อแรกจะไม่นำมาใช้เมื่อวิซาร์ดพยายามใช้ดาบ
ฉันชอบแนวคิดนี้ในหลักการ แต่มีข้อกังวลเกี่ยวกับวิธีการใช้ในทางปฏิบัติ
ไม่มีอะไรน่าจะป้องกันไม่ให้นักพัฒนาจากหลีกเลี่ยงCommandsและRules โดยเพียงแค่การตั้งค่าบนWeapon คุณสมบัติความต้องการที่จะเข้าถึงได้โดยคำสั่งดังนั้นจึงไม่สามารถที่จะทำPlayerWeaponWieldprivate set
ดังนั้นสิ่งที่ทำให้นักพัฒนาไม่สามารถทำสิ่งนี้ได้? พวกเขาแค่จำไม่ได้ใช่ไหม