Я намагаюся моделювати карткову гру, де карти мають два важливі набори функцій:
Перший - ефект. Це зміни в ігровому стані, які відбуваються під час гри в карту. Інтерфейс для ефекту такий:
boolean isPlayable(Player p, GameState gs);
void play(Player p, GameState gs);
І ви можете вважати карту граючою, якщо і лише якщо ви зможете задовольнити її вартість і всі її наслідки відтворювати. Так:
// in Card class
boolean isPlayable(Player p, GameState gs) {
if(p.resource < this.cost) return false;
for(Effect e : this.effects) {
if(!e.isPlayable(p,gs)) return false;
}
return true;
}
Гаразд, поки що, досить просто.
Інший набір функцій на картці - це здібності. Ці здібності - це зміни в ігровому стані, які можна активувати за бажанням. Придумавши інтерфейс для них, я зрозумів, що їм потрібен метод визначення того, чи можна їх активувати чи ні, і метод для здійснення активації. Це закінчується буттям
boolean isActivatable(Player p, GameState gs);
void activate(Player p, GameState gs);
І я усвідомлюю, що за винятком називати це "активувати" замість "грати", Ability
і Effect
мати точно такий же підпис.
Чи погано мати кілька інтерфейсів з однаковою підписом? Чи повинен я просто використовувати один і мати два набори одного інтерфейсу? Як так:
Set<Effect> effects;
Set<Effect> abilities;
Якщо так, то які кроки рефакторингу слід зробити по дорозі, якщо вони стають не ідентичними (оскільки з'являється більше функцій), особливо якщо вони розходяться (тобто обидва отримують щось інше не повинно, на відміну від одного лише отримання а інше є повним набором)? Я особливо стурбований тим, що поєднання їх стане нестабільним, як тільки щось зміниться.
Дрібний шрифт:
Я усвідомлюю, що це питання породжене розвитком ігор, але я вважаю, що це така проблема, яка може так само легко повзати в неігровій розробці, особливо при спробі розміщення бізнес-моделей декількох клієнтів в одній програмі, як це відбувається з майже кожен проект, який я коли-небудь робив з більш ніж одним впливом на бізнес ... Також використовуються фрагменти - це фрагменти Java, але це так само легко можна застосувати до безлічі об'єктно-орієнтованих мов.