Выбор дизайна: передать сервис объекту или объект сервису? - PullRequest
2 голосов
/ 15 августа 2011

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

Когда я просматривал этот ответ , на вопрос об ООП мне пришло в голову, чтоЯ собирался когда-нибудь задать этот вопрос.

Предположим, что требования и технические характеристики проекта позволяют вам выбрать один из следующих вариантов:

вариант a:

$service = new SendService();
$recipient = new Recipient( 'John', 'Doe', 'john.doe@example.com' );
$message = new Message( $service );
$message->setContent( 'Lorem ipsum...' );
$message->send( $recipient );

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

вариант b:

$service = new SendService();
$recipient = new Recipient( 'John', 'Doe', 'john.doe@example.com' );
$message = new Message();
$message->setContent( 'Lorem ipsum...' );
$service->send( $message, $recipient );

Другими словами: пусть код клиента передает сообщение (и получателю) в службу.

Есть ли какие-либо конкретные (дизайн) причина выбора одного над другим, или это просто вопрос предпочтений?

В этом конкретном случае я бы подумал, что последний вариант больше напоминает реальный пример отправки почтовой открытки.o Почтовое отделение, например, вместо того, чтобы втиснуть почтовое отделение в почтовую карточку, если вы понимаете, что у меня дрейф.И именно поэтому имеет смысл выбрать этот вариант.Или реальные метафоры не оправдывают выбор дизайна?

Ответы [ 4 ]

5 голосов
/ 15 августа 2011

Как я вижу, вариант использования можно возобновить до:

У меня есть message и message service. Мне нужно отправить message как-то, используя message service

Альтернативы:

A - message знает message service и знает, как отправить сам по себе.

И

B - message не знает о message service. message service получает message и отправляет его.

Как я вижу, в первом случае что-то подобное происходит sonner или позже (псевдокод):

Message {

   send(MessageService) = {

    // Do lot's of stuff.
    MessageService.send(this)
   }
}

Так почему бы просто не перейти с опцией B на первое место?

4 голосов
/ 15 августа 2011

$message = new Message( $service );

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

Вы эффективно ограничиваете свою гибкость практически без выгоды. Что делать, если вы хотите отправить его по электронной почте, но если это не удается, вы хотите иметь возможность спулинга к службе, которая будет повторять попытку. Хотите написать:

$message = new Message($emailService);
if (!$message->send()) {
  $message2 = new Message($spoolService);
  $message2->clone($message);
  $message2->send();
}

Или:

$message = new Message();
if (!$email->send($message)) {
  $spooler->send($message);
}

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

Я не могу лично представить единственную вескую причину, чтобы сделать вариант а.

3 голосов
/ 15 августа 2011

Тот, кому нужна наименьшая свобода относительно этого контракта , должен получить другой. Обычно в таком случае с объектом данных и службой служба должна получать объект данных. Но не всегда. В частности, в приложениях, где операции динамически связаны друг с другом, например, в качестве объектов Function, вы хотите, чтобы Сообщение принимало операции, которые должны быть выполнены.

Как отмечалось ранее, передача сервиса в конструкторе сообщения не имеет большого смысла. Но я боюсь, что это не то, о чем вы хотели спросить - другими словами, я думаю, что вы, вероятно, «должны» написать

$message->send( $service, $recipient );

чтобы сохранить яблоки и яблоки.

Ключевой степенью свободы мышления является тестируемость.

Иногда ответом является «ни один» - где требуется третий класс для инкапсуляции конкретного экземпляра операции отправки.

1 голос
/ 15 августа 2011

Ну, я думаю, что это, вероятно, открытый вопрос, если вы не имели в виду конкретные обстоятельства;но это не совсем открыто.Лично я думаю, что если у вас не было конкретной технической причины для этого, нет особой причины нарушать метафору службы, принимающей объект;однако, нет строгого и быстрого правила, согласно которому вы не можете делать такие вещи, как отправка самого сообщения.(На самом деле это напоминает мне некоторые из более ранних примеров, которые я читал, когда только собирал OO.)

Видите, хотя, возможно, у вас есть техническая причина для этого.Скажем, у вашего приложения есть несколько возможных Service с, через которые может быть отправлено Message, в зависимости от конфигурации, которая сопоставляет конкретную клиентскую систему с конкретной службой.У клиентов нет особой причины для того, чтобы знать что-либо об особенностях службы, единственное, что на самом деле нужно сделать клиентам, это составить сообщение и отправить его.Возможно, это даже в основном было реализовано, только сообщения просто регистрировались каждым компонентом, а не отправлялись через службу, и это производственная система, и вам необходимо внести абсолютный минимум изменений в систему.Или, возможно, команда просто решила, что это лучшая метафора системы.

Итак, клиентская система запрашивает Message у какого-то объекта MessagingFacade, который создает экземпляр Message, и дает емуссылка на Service и передает ее клиенту.Затем клиент может сделать с ним все, что ему нужно, скажем, передать его нескольким различным частям системы для сопоставления информации о состоянии, причем любая конкретная часть системы, возможно, является конечной точкой для записи Message в зависимости отсостояние системы и уровень ведения журнала, и вы хотите, чтобы терминальный объект мог отправлять его, не требуя (или не разрешая) всех классов, которые может быть отправителю, чтобы знать о MessagingFacade.

в ситуациитаким образом, мне кажется разумным, что само Сообщение реализует глагол отправки, чтобы составители сообщений могли просто завершить сообщение и вызвать theMessage.Send.

Итак, несмотря на то, что могут существовать «правилаПри изучении подобных вещей часть написания реальных систем распознает, что можно нарушать эти правила, особенно когда следование «нормальным» правилам приводит к нарушению метафор в других местах вашей системы.Ответ на этот вопрос, как и на многие вопросы типа «что лучше», всегда таков: что имеет смысл в моей конкретной ситуации?Упрощает ли та или иная часть других частей моей системы?Не нарушает ли одно или другое предположения в уже реализованных частях моей системы?И так далее.:)

Итак:

«Есть ли какая-то конкретная (конструктивная) причина для выбора одного над другим, или это просто вопрос предпочтений?»

Я думаюОтвет на этот вопрос: у нас нет достаточно информации, чтобы принять решение.Любые конструктивные причины будут зависеть от особенностей вашей системы.Если мы предполагаем, как и в вашем изложении, что между этими двумя вариантами действительно нет технических различий, то я думаю, что я бы придерживался традиционного взгляда на службу, отправляющую сообщение, НО я также думаю, что есть аргументбыть сделано в другом направлении.Если мы позволяем сообщению отправлять себя, мы уменьшаем связь в системе;изначально все (возможно, многие классы), которые собирались отправить сообщение, должны были знать как о Message, так и Service, тогда как мы только увеличили связь между Message и Service (только эти классы).

"В этом конкретном случае я думаю, что последний вариант больше напоминает реальный живой пример отправки почтовой карточки, например, в почтовое отделение, вместо того, чтобы втиснуть почтовое отделение в почтовую карточку, если вы получите мойи что для этого имеет смысл выбрать этот вариант. Или неужели метафоры реальной жизни не оправдывают выбор дизайна ? "

Я бы сказал, что реальные метафоры не сами по себе оправдывают выбор дизайна.Они оправдывают только в случае, когда модель системы действительно близко моделирует реальную жизнь.Здесь сложно дать общий ответ, потому что существует так много реальных метафор и так много возможных способов реализации системы.В любом конкретном случае вы можете спорить о том, является ли его моделирование с реальным миром правильным решением, но абстрактно слишком много исключений, чтобы дать твердый ответ.

...