Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/293.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 创建一个使用其他工厂来构建最终具体对象的工厂实现是否是一种良好的实践?_Php_Design Patterns_Dependency Injection_Factory - Fatal编程技术网

Php 创建一个使用其他工厂来构建最终具体对象的工厂实现是否是一种良好的实践?

Php 创建一个使用其他工厂来构建最终具体对象的工厂实现是否是一种良好的实践?,php,design-patterns,dependency-injection,factory,Php,Design Patterns,Dependency Injection,Factory,在我正在构建的应用程序中,有一个CLI入口点类: class CLIEntryPoint { protected $factory; public function __construct(ApplicationObjectFactoryInterface $factory) { $this->factory = $factory; } public function run(...$args) { $choice = $args[1]

在我正在构建的应用程序中,有一个CLI入口点类:

class CLIEntryPoint {

   protected $factory;

   public function __construct(ApplicationObjectFactoryInterface $factory) {
      $this->factory = $factory;
   }

   public function run(...$args) {
      $choice = $args[1];
      $appObject = $this->factory->makeApplicationObject($choice);
      $appObject->doApplicationRelatedStuff();
   }
}
这个入口点是在我的“front controller”脚本中使用依赖项注入创建的,它接收一个
ApplicationObjectFactoryInterface
实现(实际上,
ApplicationObjectFactoryInterface
的当前实现是由DI容器注入的,DI容器反过来从其配置文件中读取它,但这不是重点)

ApplicationObjectFactoryInterface
的当前实现也使用DI,并且依赖于帮助其构建最终应用程序对象的其他工厂:

class CurrentImplementationOfApplicationObjectFactory implements ApplicationObjectFactoryInterface {

   protected $someComponentFactory;
   protected $anotherComponentFactory;

   public function __construct(SomeComponentFactoryInterface $someComponentFactory, AnotherComponentFactoryInterface $anotherComponentFactory) {
      $this->someComponentFactory = $someComponentFactory;
      $this->anotherComponentFactory = $anotherComponentFactory;
   }

   /**
   * Interface's method
   * 
   * @return ApplicationObjectInterface
   */
   public function makeApplicationObject($choice) {
      $component = $this->someComponentFactory->makeSomeComponent();
      $anotherComponent = $this->anotherComponent->makeAnotherComponent();
      switch ($choice) {
         case 1:
            return new CurrentImplementationOfApplicationObject1($component, $anotherComponent);
         case 2:
            return new CurrentImplementationOfApplicationObject2($component, $anotherComponent);
         default:
            return new DefaultImplementationOfApplicationObject($component, $anotherComponent);
      }
   }

}
这里的
CurrentImplementationOfApplicationObject1
CurrentImplementationOfApplicationObject2
DefaultImplementationOfApplicationObject
都实现了
ApplicationObjectInterface
接口,因此它们都具有
doApplicationRelatedStuff
方法

我想知道像我这样编写代码是否是一种好的做法,如果不是,我如何改进它

基本上,我在这里创建一个依赖于其他组件的组件,以便使用工厂正常工作,而工厂又需要内部工厂来构建实现
ApplicationObjectInterface
接口的组件

这被认为是良好的做法吗

一如既往,感谢您的关注

编辑:我看了Steven的文章,试图重构CLIEntryPoint。现在唯一的问题似乎是如何将
$choice
参数传递给工厂,当
运行()时,工厂现在位于代理内部调用了
方法。此代码结构是否比我上面发布的代码结构好?当然,
某些ComponentFactoryInterface
和另一个ComponentFactoryInterface应该遵循相同的行为(使用它们的工厂不应该直接使用它们,而是通过两个代理来实现,
SomeComponentInterface
另一个ComponentInterface
)。无论如何,我希望我做对了,下面是代码:

class CLIEntryPoint {

   protected $applicationObject;

   public function __construct(ApplicationObjectInterface $applicationObject) {
      $this->applicationObject = $applicationObject;
   }

   public function run(...$args) {
      $choice = $args[1]; // How do I deal with different choices when I am using a Proxy? I should have different application objects depending on input.
      $this->applicationObject->doApplicationRelatedStuff();
   }
}

interface ApplicationObjectInterface {

    public function doApplicationRelatedStuff();

}

class ApplicationObjectProxy implements ApplicationObjectInterface {

    protected $applicationObjectFactory;
    protected $applicationObjectImplementation = NULL;

    public function __construct(ApplicationObjectFactoryInterface $factory) {
        $this->applicationObjectFactory = $factory;
    }

    public function __call($method, $args) {
        // Calling interface's
        $implementation = $this->getImplementation();
        $methodOfInterfaceToCall = preg_replace('/Proxy$/', '', $method);
        return $implementation->{$methodOfInterfaceToCall}(...$args);
    }

    /**
     * Laxy loading method.
     */
    protected function getImplementation() {
        if (is_null($this->applicationObjectImplementation)) {
            $this->applicationObjectImplementation = $this->applicationObjectFactory->makeApplicationObject(); // Choice should go here somehow...
        }
        return $this->applicationObjectImplementation;
    }

    public function doApplicationRelatedStuff() {
        // This will call the PHP's magic `__call` method, which in turn will forward the call to the application object's
        // implementation returned by the factory.
        return $this->doApplicationRelatedStuffProxy();
    }

}

事实上是的,这是一种称为抽象工厂模式的模式。因此,我在本科期间在全班同学面前展示了一个例子:

因此,如果您正在制作视频游戏第一人称射击游戏,您可能需要创建三个具体工厂,如:

  • 飞怪工厂
  • 游泳厂
  • 步行工厂
  • 所有这些工厂都将实现一个抽象工厂

    有了这个,你可以让你的视频游戏创建一个等级,在这个等级中你想要相同类型的怪物的波浪,因此你可以让一个randomWaveMonsterGenerator方法返回一个怪物工厂,这个怪物工厂可能已经返回了一个具体的SwimmingMonsterFactory。然后你将有一个SwimmingMonsterFactory生成的SwimmingMonster波浪


    因此,请更直接地回答您的描述,查看上面的代码,您询问了关于依赖项注入的选择问题。对于依赖项注入,我相信对于这种模式,您必须在代码尝试实现之前注入每个具体类班级

    例如:

    • 上面的代码说run方法给出了一个名为 选择
    • 使用此选项,必须将其用作getImplementation方法的参数
    • getImplementation方法依赖于依赖关系的所有具体对象 在调用getImplementation方法之前,必须先创建注入
    • 但是,由于您不知道将调用哪个实现类,我相信您必须先注入所有实现类
    • 然后,您可以使用选项变量作为参数来获得正确实现的factory类

    希望这有帮助!

    您应该阅读。感谢您的洞察力!我希望我做对了。请检查我的编辑。我试图重构我的代码,以便
    CLIEntryPoint
    现在取决于应用程序对象的接口。然后有一个实现充当代理并将其调用转发到实际实现的调用,这是我从一个内部工厂获得的,它现在是代理的内部工厂,因此不是
    CLIEntryPoint
    的依赖项。我现在的问题是初始的
    $choice
    参数,我现在不知道如何传递到工厂,因为我已经将其移动到代理内部了……您能评论我的代码吗?