Как стать автором
Обновить

Комментарии 6

НЛО прилетело и опубликовало эту надпись здесь
На мой взгляд получилось очень странно и мимо.

В описательной части стандарта psr упоминаются следующие варианты использования:

1. одностороннее уведомление — «Я сделал что-то, если тебе интересно»
2. улучшение объекта — «Вот вещь, пожалуйста, измените её, прежде чем, я что-то с ней сделаю»
3. коллекция — «Дайте мне все ваши вещи, чтобы я мог что-то сделать с этим списком»
4. альтернативная цепочка — «Вот вещь, первый из вас кто справится с этим, сделает это, затем остановиться»


Там же, чуть дальше, рабочая группа в результате обсуждения пришла к следующему:
— коллекция, это тоже вещь, потому пункты 2 и 3 это одно и то же.
— поскольку объекты всегда передаются по ссылке, пункт 1 это лишь частный случай пункта 2
— для пункта 4 добавить интерфейс StoppableEventInterface

В результате разработчик (Б) по сигнатуре видит все необходимое.
Поскольку, уже второй комментарий с упоминанием, передачи объекта по ссылке.

поскольку объекты всегда передаются по ссылке, пункт 1 это лишь частный случай пункта 2


Это верно, только когда передаваемые объекты содержат методы изменения данных. В случае простого DTO объекта, изменить, его нельзя.

Пример:

interface CustomerNameInterface {

    public function firstName(): string;

    public function lastName(): string;

    public function middleName(): ?string;
}


interface customerNameChangedListener {

    public function onCustomerNameChange(
        int $customerId, 
        CustomerNameInterface $customerName
    );
}


Это только оповещение, без возможности изменения переданного объекта.

interface customerNameBeforeChangeListener {

    public function onBeforeCustomerNameChange(
        int $customerId, 
        CustomerNameInterface $customerName
    ): CustomerNameInterface

}


Тут, явно описано, что обработчик может изменить объект, или даже подменить его реализацию.

И повторюсь, интерфейс CustomerNameInterface при разработке уже есть в системе, в описанном способе дополнительный объект «сахар» CustomerEvent не нужен.
Это верно, только когда передаваемые объекты содержат методы изменения данных. В случае простого DTO объекта, изменить, его нельзя.

Наверное я еще не проснулся, и ннада больше кофе. Или вы действительно предлагаете «для изменения неизменяемых объектов просто используем подмену объектов»? Тогда не понятно, зачем у вас вообще методы у объекта — сделайте просто все свойства пабликами.
При этом все еще не ясно, каким образом вы собираетесь изменять этот объект внутри листенера. Максимум что вы можете — вытащить имя другого кастомера и вернуть его вместо оригинала.

И повторюсь, интерфейс CustomerNameInterface при разработке уже есть в системе, в описанном способе дополнительный объект «сахар» CustomerEvent не нужен.

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

interface LogChangesEvent {

    public function getObjectIdentifier(): string;

    public function getOldValue(): JsonSerializable;

    public function getNewValue(): JsonSerializable;
}


interface SmsNotifyEvent {

    public function getRecipient(): string;

    public function getText(): string;
}


interface CustomerNameChangedEvent implements SmsNotifyEvent, LogChangesEvent {
    public function getCustomerName(): CustomerNameInterface;
}


Ну и сообветственно набор листенеров, которые слушают тот же SmsNotifyEvent — они ничего не знают ни про кастомера, ни про его CustomerNameInterface.
По моему мнению, это обсуждение начинает скатываться в «холивар» по реализациям. Что, в свою очередь уведет от сути. Я специально в статье обходил, моменты, которые могут свести все к разнообразным «холиварам» не по теме.

В приведенном Вами примере, больше вопросов чем ответов. «Холиварных», вопросов.

Вопросы:

  1. Интерфейс CustomerNameChangedEvent, какому пакету (модулю, банду, скопу) принадлежит? Сервису, который отвечает за изменение данных клиента?
  2. Интерфейс SmsNotifyEvent, какому пакету (модулю, банду, скопу) принадлежит? Сервису, который отвечает за sms отправку?
  3. Интерфейс LogChangesEvent, какому пакету (модулю, банду, скопу) принадлежит? Сервису, который отвечает за логирование?


По описанному вами коду, я вижу 3 разных задачи:. Изменение имени, смс информирование, и логирование. При этом основной задачей является изменение имени. Остальные второстепенные.

По вашему коду получаются связи: Клиент зависит от смс и логирования, что по мне в корне не корректно, так как связь должна быть обратной. смс и логирования может не быть, это второстепенный функционал.

Исходя из этого смс и логирования, должны быть слушателем, а не частью события на кейсе изменения имени клиента.
Так давайте не будем все скатывать в холивар по реализациям. Честно говоря мне просто было лень думать над названиями классов, так что я ткнул первое что пришло в голову.

По вашему коду получаются связи: Клиент зависит от смс и логирования, что по мне в корне не корректно, так как связь должна быть обратной. смс и логирования может не быть, это второстепенный функционал.

Ну пусть это будет система смс рассылок, и этот функционал будет обязательным. Связь же у нас исключительно через реализацию интерфейсов, так что не вижу в этом ничего противоестественного. Так предлагаю остановиться на том что у нас в системе есть модуль в котором описаны ключевые интерфейсы связей между модулями.

В любом случае суть не в этом. Сейчас мы имеем два варианта реализации
— ваш пример, в котором при добавлении логирования мы должны будем подписаться на сотню эвентов смены имени/адреса/и т.д., зато все модули абсолютно независимы.
— мой пример, где про добавлении логирования нужно подписаться только на LogChangesEvent, но при этом модули зависят от общего модуля с описанием интерфейсов.

На мой взгляд, в зависимости от системы, любой из этих вариантов имеет право на жизнь. А обсуждать какой из них лучше я даже не предлагаю.

Тем не менее — эта часть ветки действительно уходит в тупик, т.к. мы перешли к обсуждению лишь части комментария, суть которого была привести пример когда «дополнительный объект «сахар» CustomerEvent» таки нужен.

Вообще, перечитав статью, возникло ощущение что вас просто напрягает древняя реализация эвентов в zf, но Вы зачем-то приплели сюда еще и psr-14, который вообще по сути только про диспетчер. Посмотрите например на реализацию тут github.com/phly/phly-event-dispatcher — позволяет все что вы хотите, и без костылей типа двух разных методов в диспетчере.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории