【问题标题】:Best practice to implement Factory pattern using Symfony2使用 Symfony2 实现工厂模式的最佳实践
【发布时间】:2016-02-25 19:25:31
【问题描述】:

我正在制作一个可以发送电子邮件或短信的信使,并且可以现在发送或稍后发送(信息保存在数据库中)。我已经提出了 2 个解决方案,但都没有让我满意。

我是把代码集中在一个Factory中,Factory模式的代码很简单:

class MessageFactory
{
     static public function get($type,$em)
     {
          $instance = null;
          switch ($type) {
              case 'email':
                    $instance = new EmailMessage($em);
                    break;
   ....
  return $instance;
}

class EmailMessage implements MessangerInterface
{
 ...
   public function send( $eMessage,array $receivers, $time=NULL)
   {

interface MessangerInterface
{
  public function send($message,array $receivers);
}

第一种解决方案:只需像普通静态方法一样调用

$messanger = Factory\MessageFactory::get('email',$em);
$messanger->send($eMessage, array('tom'=>'tom@gmail.com'));

这是一个糟糕的解决方案,因为我需要将 Doctrine Manager 作为参数传递给方法

第二个解决方案:将其用作 Symfony 2 服务

services:
my.messanger:
    class: Bundle\Factory\MessangerInterface
    factory_class: Bundle\Factory\MessageFactory
    factory_method: get
    arguments:
        messanger_type: %messanger.type%

并且还将 Doctrine 作为参数传入。但是使用这样的解决方案我不能在我的代码中选择 messanger.type,它使用配置参数定义为emailsms;我需要有代码选择类型的能力。

我还有一个问题是在课堂上我需要发送电子邮件或短信,这意味着我需要一个外部服务,得到它是这样的:

class EmailMessage implements MessangerInterface
{
 if ('AppCache' == get_class($kernel)) {
      $kernel = $kernel->getKernel();
   }
 $kernel->getContainer()->get('mailer')->send($eMessage);

这似乎是一种非常糟糕的做法。

请问,您能告诉我任何更好的解决方案吗?

我想遵循“瘦控制器胖模型”的概念。

【问题讨论】:

    标签: symfony factory-pattern


    【解决方案1】:

    似乎使用 Symfony 2 服务的选项 2 是最好的。

    我考虑过建议你让工厂成为服务,并传入类型以获取 Messenger 实例,而不是在配置中修复它,但如果你想要的只是每种类型的 Messenger 中的一种,那就是无济于事(工厂将继续创造越来越多的信使)。因此,我认为您需要定义两个服务,每个 Messenger 一个。

    如果您不想在 Messenger 中获取其他服务,则需要在获取 Messenger 时将其注入。

    例如

    services:
        mailer:
            class: Mailer
        smser:
            class: SMSer
    
        email.messanger:
            class: Bundle\Factory\MessangerInterface
            factory_class: Bundle\Factory\MessageFactory
            factory_method: get
            arguments:
                messanger_type: email
                sender: @mailer
        sms.messanger:
            class: Bundle\Factory\MessangerInterface
            factory_class: Bundle\Factory\MessageFactory
            factory_method: get
            arguments:
                messanger_type: sms
                sender: @smser
    

    你的工厂需要接受新的 $sender 参数:

    class MessageFactory
    {
         static public function get($type,$em,$sender)
         {
              $instance = null;
              switch ($type) {
                  case 'email':
                        $instance = new EmailMessage($em, $sender);
                        break;
       ....
      return $instance;
    }
    
    interface MessangerInterface
    {
        public function send($message,$sender, array $receivers);
    }
    

    然后,当您调用它时,您会专门要求其中一个信使:

    $this->get('email.messenger')->send($emailMessage);
    $this->get('sms.messenger')->send($smsMessage);
    

    【讨论】:

    • 完美!但是如果我有一个推进对象的工厂,它是如何工作的,我应该将推进对象声明为服务吗?
    • 你是什么意思,“推进物体的工厂”?你的工厂创建了一个推进对象,还是别的什么?
    • 可以说 EmailMessage 或 SmsMessage 是推进对象,我必须将它们声明为服务吗?如果我有一个包含 50 个对象的项目,我必须将它们全部声明为服务,有没有办法轻松做到这一点?
    • 将事物定义为服务允许您确保只有其中一个,全局访问它们,并自动将它们提供给其他服务。自从我完成 Propel 已经有一段时间了,但是你没有存储库或实体管理器,你只有实体和静态方法吗?所以我很想说你不需要定义任何额外的服务来使用 Propel,你只需在你的代码中创建对象或使用静态方法。不过,如果您需要,我会问一个单独的问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-04
    • 1970-01-01
    • 2013-02-06
    • 1970-01-01
    • 2015-09-02
    相关资源
    最近更新 更多