Фабричный дизайн шаблона реализации сомнений

Я пытаюсь создать бота для мессенджера Telegram, пытаясь изучить ООП. Я действительно потерялся в том, как подойти к проблеме. У меня есть сущность Message, со всеми получателями и установщиками, это, я думаю, довольно прямолинейно. Моя проблема в том, что я хочу создать два (или более) типа фабрик

1) простое сообщение где вы просто кормите фабрику с помощью chat_id, который вы хотите отправить сообщение и текст, это может быть что-то вроде этого:

<?php

namespace Telegram\Domain\Factory;

use Telegram\Domain\Entity\Message;

class MessageRaw extends MessageAbstract {
public function createMessage($chat_id, $text) {
$message = new Message();
$message->setChatId($chat_id);
$message->setText($text);

return $message;
}
}

где MessageAbstract находится

<?php

namespace Telegram\Domain\Factory;

abstract class MessageAbstract {
abstract public function createMessage($chat_id, $text);
}

2) сообщение с клавиатуры (Telegram дает вам возможность включить пользовательскую клавиатуру при отправке сообщения). У меня проблема здесь, клавиатура задается в виде массива, так что это будет еще один аргумент для createMessage.

Поэтому моя проблема заключается в том, должен ли я всегда указывать аргумент $ keyboard, является ли это простым сообщением или сообщением с клавиатурой? Или эти два типа сообщений достаточно различны, чтобы их можно было создавать из разных классов (я думаю, что нет)? Или, может быть, я не должен делать это на фабрике, но с сеттерами и геттерами?

TLDR: Как создать объект с разным количеством аргументов необычным способом, что-то вроде этого

$MessageRaw = new MessageRaw($chat_id, $text);
$MessageNumericKeyboard = new MessageNumericKeyboard($chat_id, $text); //numeric keyboard is standard so can be set in the createMessage Function
$MessageCustomKeyboard = new MessageCustomKeyboard($chat_id, $text, ['A', 'B']); //should it be done like this?

6

Решение

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

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

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


РЕДАКТИРОВАТЬ:

впрыскивание (Примечание: я включил параметр типа, чтобы охватить одну возможную технику расширения через строку, но это также может быть и сам объект с внедренным типом, вплоть до вас. Также включена опция одновременного внедрения атрибутов вашего сообщения для конструктор сообщений, так что вы получите полностью экземплярный объект, а не пустой DTO)

class MessageFactory {
public static function get($type,$attributes=NULL,$keyboard=NULL) {
if ($keyboard && !($keyboard instanceof MessageKeyboardInterface)) {
// ... trigger some exception here
} elseif (!$keyboard) {
$keyboard = new BasicKeyboard();
}
switch($type):
case('standard'):
return new StandardMessage($attributes,$keyboard);
break;
case('short'):
return new ShortMessage($attributes,$keyboard);
break;
case('long'):
return new LongMessage($attributes,$keyboard);
break;
endswitch;
}
}

Таким образом, все ваши Message объекты могут использовать один и тот же интерфейс, могут использовать пользовательские или базовые клавиатуры и могут быть легко расширены. Конечно, вы можете расширить атрибуты $ и использовать ваши индивидуальные сеттеры после создания экземпляра, или зациклить их в конструкторе, если их много. Лично мне не нравится куча параметров в конструкторе, и я предпочел бы перебрать массив необязательных параметров.

4

Другие решения

Это выглядит как лучше подходит для общий или сад субтипирование, а не использование фабричного шаблона, например:

class Message {

// e.g.
protected $chatId;
protected $text;

// constructor
public function __construct($chatId, $text) {
$this->setChatId($chatId);
$this->setText($text);
}

// ... stuff
}

final class MessageCustomKeyboard extends Message {

// e.g.
private $_keyboard;

// constructor overrides parent
public function __construct($chatId, $text, array $keyboard) {
parent::__construct($chatId, $text);
$this->setKeyboard($keyboard);
}

// ... stuff
}

$message = new Message(1, "Hello World");
$messageCustomKeybaord = new MessageCustomKeyboard(2, "Hello again", array("a", "b"));
2

По вопросам рекламы [email protected]