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