工厂设计模式实施疑点

时间:2015-11-16 15:43:32

标签: php oop factory-pattern

我试图在尝试学习OOP的同时为Telegram信使创建机器人。我真的迷失了如何处理这个问题。我有一个消息实体,包含所有的getter和setter,我认为它非常直截了当。我的问题是我想创建两种(或更多)类型的工厂

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)带键盘的消息(电报可让您在发送消息时包含自定义键盘)。我有问题,键盘是作为一个数组给出的,所以这将是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?

2 个答案:

答案 0 :(得分:4)

我同意@ CD001有关子类型/扩展的内容,所以我不会重复他的答案,但你仍然可以通过使用依赖注入识别所需类型并返回适当的对象来使用工厂模式。

您可以在工厂方法中包含此依赖项的专用参数,也可以使用方法重载来注入它,并仅检查这些特定类型(如果有其他类可能在指定的两个之外返回)

坚持工厂模式将真正帮助你在没有太多额外工作的情况下扩展这一目标,现在偷工减料只会导致疼痛。

编辑:

注入 (nb:我已经包含了一个类型参数,通过字符串覆盖一种可能的扩展技术,但这也可以很容易地成为一个注入类型的对象,由你决定。还包括为消息构造函数同时注入Message属性的选项,因此您将获得完全实例化的对象而不是空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对象都可以使用相同的界面,可以使用自定义或基本键盘,并且可以轻松扩展。你当然可以扩展$属性并在实例化后使用你的个人setter,或者如果你有很多,可以在构造函数中循环它们。我个人不喜欢contsructor中的大量参数,而是宁愿遍历一系列可选参数。

答案 1 :(得分:2)

这看起来更适合 common或garden 子类型,而不是使用Factory模式,例如:

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"));