У цій серії публікацій блогу Ерік Ліпперт описує проблему в об'єктно-орієнтованому дизайні, використовуючи в якості прикладів майстрів та воїнів, де:
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
клас відповідав за те, щоб майстер міг використовувати лише персонал). Ви порушуєте Принцип заміни Ліскова, ризикуєте виключити час виконання або закінчите кодом, який важко розширити.
Рішення, яке він придумує, полягає в тому, що клас перевірки не проводиться перевірки. Він використовується лише для відстеження стану. Тоді замість того, щоб дати гравцеві зброю:
player.Weapon = new Sword();
стан модифікується Command
s і відповідно до Rule
s:
... ми робимо
Command
об'єкт під назвою,Wield
який займає два об'єкти стану гри, aPlayer
і aWeapon
. Коли користувач видає команду системі "цей майстер повинен володіти цим мечем", тоді ця команда оцінюється в контексті наборуRule
s, який створює послідовністьEffect
s. У нас є одна,Rule
яка говорить про те, що коли гравець намагається скласти зброю, наслідком є те, що існуюча зброя, якщо така є, скидається, а нова зброя стає зброєю гравця. У нас є ще одне правило, яке посилює перше правило, яке говорить про те, що ефекти першого правила не застосовуються, коли майстер намагається обрушити меч.
Мені в принципі подобається ця ідея, але я хвилююсь, як вона може бути використана на практиці.
Здається, ніщо не заважає розробнику обійти Commands
і Rule
s, просто встановивши значення Weapon
a Player
. Weapon
Власності повинні бути доступні по Wield
команді, так що це не може бути зроблено private set
.
Отже, що ж запобігти розробник робити це? Вони просто повинні пам’ятати, щоб цього не робити?