PHP工厂方法

时间:2016-12-12 14:47:46

标签: php design-patterns

我正在阅读工厂方法。有人可以解释为什么建议工厂方法位于一个单独的工厂类中吗?

我从这里开始我的例子:http://www.devshed.com/c/a/PHP/Design-Patterns-in-PHP-Factory-Method-and-Abstract-Factory/

class ETF {
  var $data;
  function __construct($data) {
    $this->data = $data;
  }
  function process() {}
  function getResult() {}
}

class VirtualCheck extends ETF {}
class WireTransfer extends ETF {}

class ETFFactory {
  function createETF($data) {
      switch ($data[‘etfType’]) {
      case ETF_VIRTUALCHECK : 
        return new VirtualCheck($data);
      case ETF_WIRETRANSFER :
        return new WireTransfer($data);
      default :
        return new ETF($data);
      }
  }
}

$data = $_POST;
$etf = ETFFactory::createETF($data);
$etf->process();

我倾向于这样写:

class ETF {
    final public static function factory($data) {
        switch ($data[‘etfType’]) {
            case ETF_VIRTUALCHECK :
                return new VirtualCheck($data);
            case ETF_WIRETRANSFER :
                return new WireTransfer($data);
            default :
                return new ETF($data);
        }
    }

    var $data;
    function ETF($data) {
        $this->data = $data;
    }
    function process() {}
    function getResult() {}
}

class VirtualCheck extends ETF {}
class WireTransfer extends ETF {}

$data = $_POST;
$etf = ETF::factory($data);
$etf->process();

这样做我错了吗?

2 个答案:

答案 0 :(得分:3)

我不会说你错了"但是有一种"气味"。通过结合制造类中的工厂方法,该体系结构违反了SOLID指南中的一些:

  1. 单一责任:班级现在做两件事(当它应该做一件事)。
  2. 开放/封闭原则:班级只有半开(当它应该完全打开时)。
  3. 接口隔离:类的消费者使用制造对象的正确方法,没有工厂,反之亦然(消费者应该只依赖于所需的方法)
  4. 我发现一个班级的SOLID越多,班级就越容易长期维持。因此,我不会认为SOLID违规是直接问题,只是可能出现故障的信号。

    那么,你可能遇到什么麻烦?好吧,如果工厂本身变得更加复杂,那么您将需要方法来处理这些额外的工作。这些方法不会被类正确的方法所使用。所以你最终会得到这样的代码:

    class ETF {
        final public static factory($kind) {
            switch ($kind) {
            case 'A':
                $etf = static::factoryHelperForA();
                break;
            case 'B':
                $etf = static::factoryHelperForA();
                break;
            }
            return $etf;
        }
    
        public function apiMethod1() {
            $this->apiMethod1Helper();
        }
    
        public function apiMethod2() {
            $this->apiMethod2Helper();
        }
    
        // factory helper
        private static function factoryHelperForA() {
            /* lots of code */
        }
    
        // another factory helper
        private static function factoryHelperForB() {
            /* lots of code */
        }
    
        // ugh, now we have api method helpers... totally different responsibility
        private function apiMethod1Helper() {
            /* lots of code */
        }
    
        // still more...
        private function apiMethod2Helper() {
            /* lots of code */
        }
    }
    

    因此,随着工厂需求的增长,以及制造类的需求增长,您可以看到它开始变得混乱。这就是SOLID原则引导您远离的目标。

    如果现在对于构建未来灵活课程非常重要,那么我建议将工厂淘汰到自己的{{> 1}} class。

答案 1 :(得分:0)

我怀疑有一些工厂方法和抽象工厂术语的错误。

工厂方法允许我们指定一些我们希望在代码中使用的对象的接口,但是目前还不知道它的实现,或者我们只知道一些默认的实现可能是不同的一些案例。所以我们把这个决定留给了子类。另一种可能的用法是隐藏对象创建细节或定义类似构造函数的方法以便更简单地使用。

抽象工厂提供了一个用于创建相关对象族的界面。我们在想要将整个创建过程与使用隔离时使用它。例如,我开发了几种不同的回合制纸牌游戏。所有游戏都是不同的,并且具有不同的逻辑(玩家的差异数,差异组合,转弯顺序,点数系统等)。但由于它们是基于回合制的纸牌游戏,所以它们在同一时间(从差异角度):你等待足够数量的玩家(每个游戏的每个玩家对象都是差异),你有一个经销商(另一个封装的对象)规则并且是每个实现的差异)并且你运行游戏只是在玩家之间切换转弯直到某些条件发生。所以我能够使用我使用diff abstract factory implementation初始化的相同游戏框架。

关于你的问题。在您的情况下,您有一个最终的静态类似构造函数的方法。从技术上讲,它违反了单一责任原则,但我认为这与讨论相关“我们应该在实例上调用静态方法”。如果我们不在实例上调用静态方法,则它什么都不违反。在我看来,它是工厂方法的有效用法,你不会对这段代码有任何问题。

有用的链接: