2014-09-30 89 views
5

我正在制作一个可以发送电子邮件或短信的信使,并且可以立即发送或稍后发送(信息保存在数据库中)。我做了2个解决方案,但都不满足我。使用Symfony2实现工厂模式的最佳实践

我在集中一个工厂代码和工厂模式的代码非常简单:

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

1号方案:只需拨打作为一个普通的静态方法

$messanger = Factory\MessageFactory::get('email',$em); 
$messanger->send($eMessage, array('tom'=>'[email protected]')); 

这是一个不好的解决方案,因为我需要将一个Doctrine Manager作为参数传入方法

第二溶液:要使用它作为一个Symfony的2服务

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

以及在学说作为参数传递。但是使用这样的解决方案我不能在我的代码中选择messanger.type,它使用配置参数定义为emailsms;我需要有代码选择类型的能力。

我也有这个类里面我需要发送电子邮件或短信的问题,这意味着我需要一个外部的服务,得到这样的:

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

这似乎是非常不好的做法。

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

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

回答

6

看起来像选项2,使用Symfony 2服务,将是最好的。

我认为建议您让Factory成为服务,并将类型传入以获取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); 
+0

完美!但是如果我有一个推进物体的工厂,那么它是如何工作的,我是否应该将推动物体作为服务来声明? – julestruong 2016-11-22 17:30:50

+0

你是什么意思,“推动物体的工厂”?你的工厂创建了一个推动对象,还是其他的东西? – frumious 2016-11-25 16:15:31

+0

假设EmailMessage或SmsMessage是推动对象,我必须将它们声明为服务对象? 如果我有一个有50个对象的项目,我必须将它们全部声明为服务,是不是有办法轻松做到这一点? – julestruong 2016-11-25 17:36:12