为了账号安全,请及时绑定邮箱和手机立即绑定

在 PHP Symfony 4.4 中编写一个类,使用设计模式 Factory Method

在 PHP Symfony 4.4 中编写一个类,使用设计模式 Factory Method

PHP
隔江千里 2022-05-27 16:14:00
使用激活自动装配的 Symfony 4.4,我想使用设计模式 FactoryMethod 实例化一个类。实例化的类是具有传递给构造函数的自动装配参数的服务。如果在工厂方法中实例化的每种类型的类的构造函数都相同,则它会很好地工作。但是,每个要实例化的服务都必须自动装配一些特定的服务才能工作。我发现我们可以使用“setter 依赖注入”。描述它的文章:https://symfonycasts.com/screencast/symfony-fundamentals/logger-traithttps://symfony.com/doc/4.4/service_container/injection_types.html#setter-injection我试图实现 setter 依赖注入,但里面的代码永远不会执行。考虑到这些文章,我们应该在调用 __construct 方法后立即使用 PHPDoc“@required”输入设置器(据我了解)。它不适用于我的代码(见下文)。我的实现是否正确?有更好的方法吗?
查看完整描述

1 回答

?
侃侃无极

TA贡献2051条经验 获得超10个赞

为了在 Symfony 中使用设计模式工厂方法,请使用服务定位器在控制器外部提供自动装配。将代码重构为以下内容:


// Controller

/**

 *@Route("/my_action/{param}")

 */

public function my_action (ThingManagerFactory $thingManagerFactory, $param)

{

    $thingManager = $thingManagerFactory->get($param);

    $thingManager->doSomething();

}



// ThingManagerFactory

use App\Locator\ThingLocator;

class ThingManagerFactory

{

    private $locator;


    public function __construct(ThingLocator $locator)

    {

        $this->locator = $locator;

    }


    public function get($param): ThingManagerInterface

    {

        if($param == 1) {

            return $this->locator->get(Thing1Manager::class);

        } elseif($param == 2) {

            return $this->locator->get(Thing2Manager::class);

        }


        throw new \InvalidArgumentException("...");

    }

}



// ServiceLocatorInterface

interface ServiceLocatorInterface

{

    public function get(string $id);

}



// ThingLocator

class ThingLocator implements ServiceLocatorInterface, ServiceSubscriberInterface

{

    private $locator;


    public function __ construct(ContainerInterface $locator)

    {

        $this->locator = $locator;

    }


    public function get(string $id)

    {

        if (!$this->locator->has($id)) {

            throw new \Exception("The entry for the given '$id' identifier was not found.");

        }


        try {

            return $this->locator->get($id);

        } catch (ContainerExceptionInterface $e) {

            throw new \Exception("Failed to fetch the entry for the given '$id' identifier.");

        }

    }


    public static function getSubscribedServices()

    {

        return [

            Thing1Manager::class,

            Thing2Manager::class,

        ];

    }

}



// ThingManagerInterface

interface ThingManagerInterface

{

    public function doSomething();

}



// Thing1Manager

class Thing1Manager implements ThingManagerInterface

{

    // ...

    private $spec1Manager;


    public function __construct($firstManager, $secondManager, $thirdManager, $spec1Manager)

    {

        // ...

    }


    // This setter is no more needed. This manager can be added to the constructor method.

    // **

    // * @required

    // */

    //public function setSpecificManager(Spec1Manager $spec1Manager)

    //{

        // if not commented, this code would be called thanks to the Service Locator (which is a Symfony Service Container)

    //    $this->spec1Manager = $spec1Manager;

    //}


    public function doSomething()

    {

        // ...

    }

}


查看完整回答
反对 回复 2022-05-27
  • 1 回答
  • 0 关注
  • 90 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信