symfony - 使用 Symfony2 实现工厂模式的最佳实践

标签 symfony factory-pattern

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

我将代码集中在一个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);

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

请问您能建议我更好的解决方案吗?

我想遵循“瘦 Controller 胖模型”的概念。

最佳答案

看起来选项 2(使用 Symfony 2 服务)是最好的。

我考虑过建议您让 Factory 作为服务,并传递类型来获取 Messenger 实例,而不是在配置中修复它,但如果您想要的是每种类型的 Messenger 中只有一个,那就是无益(工厂会不断创造越来越多的信使)。因此,我认为您需要定义两个服务,每个服务对应一个服务。

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

例如

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

并且您的 Factory 需要接受新的 $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);

关于symfony - 使用 Symfony2 实现工厂模式的最佳实践,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26117462/

相关文章:

php - Symfony 3 - (文件路径)的定义没有类属性并且似乎引用了全局命名空间中的类或接口(interface)

Symfony 与 docker,编辑麻烦

php - 具有 Doctrine 2 二级缓存和 Symfony 3.3 的多区域缓存

php - 在 PHP 中上传和保存多个图像

java - 在Java中使用工厂设计模式

php - 依赖注入(inject)与静态

php - 定义 Magento 类名称的字符串的名称

java - 如何增加一个新类型而不需要修改工厂类?

java - 将属性传递给工厂方法

java - 简单工厂和工厂方法模式的动机