Я пытаюсь создать бота для мессенджера 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?
Я согласен с @ 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
объекты могут использовать один и тот же интерфейс, могут использовать пользовательские или базовые клавиатуры и могут быть легко расширены. Конечно, вы можете расширить атрибуты $ и использовать ваши индивидуальные сеттеры после создания экземпляра, или зациклить их в конструкторе, если их много. Лично мне не нравится куча параметров в конструкторе, и я предпочел бы перебрать массив необязательных параметров.
Это выглядит как лучше подходит для общий или сад субтипирование, а не использование фабричного шаблона, например:
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"));