Как бы вы реализовали такую архитектуру в рамках PHP?

Для понятности поясню, это касаемо карточной игры.

Есть объект, к которому может быть привязан другой объект, при том связанный объект меняет характеристики и поведение первого объекта. И удаление этого связанного объекта возвращает его к исходному состоянию

Банальный пример: есть карта оружия, к ней можно применить карту усиления, или карту, которая позволяет надевать его в обход игровых правил(переписывает метод $itemCard->canEquip($player)).

Есть идея решения «в лоб», но, надеюсь, знающие люди подскажут более изящное решение.
  • Вопрос задан
  • 2647 просмотров
Пригласить эксперта
Ответы на вопрос 8
@mayorovp
У объекта-модификатора должен быть метод combine, который возвратит скомбинированный объект. У скомбинированного объекта должен быть метод, который его снова разделит.

Иными словами, нужно что-то вроде вот этого:
Ответ написан
taliban
@taliban
php программист
Если Вы работали с зендом, то посмотрите как там устроены декораторы на форме. Так же можете посмотреть на оригинальный паттерн «декоратор», хотя в данном случае зендовская поделка больше подходит, решит Ваши проблемы на 100%.
Ответ написан
@Alexei_987
прошу прощения за Ctrl + Enter :)

необходимо создать интерфейс:
interface IDecorable {
  /**
   * @return IDecorable
   */
  removeDecorator(IDecorable $decorator);
}

декорируемый обьект должен реализовать интерфейс с помощью заглушки:
  //....
  /**
   * @return IDecorable
   */
  removeDecorator(IDecorable $decorator) {
      return $this;
  }
  //...


а все декораторы могут наследоваться от абстрактного декоратора в котором будет вот такая реализация данного интерфейса:
  //....
  /**
   * @var IDecorator
   */
  private $decorableObject;
  /**
   * @return IDecorable
   */
  removeDecorator(IDecorable $decorator) {
    if($decorator == $this) {
      return $this->decorableObject;
    }
    $decorable = $this->decorableObject->removeDecorator($decorator);
    if($decorable != $this->decoratedObject) {
       $this->decoratedObject = $decorable;
    }
    return $this;
  }
  //...


Таким образом обьекты смогут использоваться следующим образом:
$decorated = $decorated->removeDecorator($decorated); 

Такой код может удалить самый верхний декоратор обьекта или вернет сам обьект если у него нет декораторов.
Для удаления произвольного декоратора из цепочки нужно передать в качестве параметра этот декоратор или декоратор с аналогичными свойствами:
$decorated = $decorated->removeDecorator($someOtherDecorator); 
Ответ написан
@nocach
Можно сделать что-то подобное:



Подойдет, если изменения свойств карт затрагивают в основном только атрибуты (прибавить, отнять и т.д.)

в таком случае $modifier->apply($card) будет напрямую менять значения карты (например прибавит +5 к урону) $mofidier->revert($card) опять таки напрямую возвращает значения на исходную точку (отнять -5 от урона).

Плюс такого решения, что нет проблемы ромба. Если карты очень различаются набором атрибутов, то Modifier можно сделать по подобию паттерна Visitor.



Правда, тут может настать проблема с процентными модифицированиями (карта +20% урона плюс картa +5 урона дадут неправильный результат), но это можно обойти модифицировав логику ModifiebleSupport.
Ответ написан
Комментировать
kuzemchik
@kuzemchik
Студенты делали как семестровую работу игру Манчкин. Такие бонусы считались уже функцией стола, а сами показатели доставались по общему интерфейсу. Соответственно, карта бонуса сама получала на вход карту на которую бонус применялся, и возвращала свой личный бонус, применимый в конкретном случае (в том числе и решала, может быть она применена к текущей карте или нет).
Ответ написан
andrew_tch
@andrew_tch
А как на тему простого EventDispatcher'a / EventListener'a? У нас есть событие GetCardPropeties, которое перезватывает стол или карта и модифицирует флаги события в зависимости от контекста.

И да, от PHP это решение не зависит )
Ответ написан
@Alexei_987
Привет. Думаю что все же проблема может быть решена с помощью обычного паттерна декоратор.
Единственно отличие то что вам необходимо иметь возможность снимать с обьекта его декораторы.
Для решения этой проблемы я предложил бы реализовать следующее решение:
Ответ написан
Комментировать
red_pilot
@red_pilot
Это шаблон стратегия, разве нет?
ru.wikipedia.org/wiki/Стратегия_(шаблон_проектирования)
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы