如何在不使用代理模式的情况下打破和改善循环依赖?

How to break and improve cyclic dependency without using proxy pattern?

我的 类 依赖太多其他 类,我找不到改进它的方法。问题如下:

我有一个 ProductRepo、ProductFactory 和一个 ImageFactory 类。 ProductRepo 在产品 table 上执行数据库操作,并将行作为数组获取。该数组传递给 ProductFactory 以创建产品模态。 产品模态也有链接到它的图像。

客户代码:

$products = $this->productRepo->findAll('...');
foreach($products as $product){
    ...
    //get images
    $images = $product->getImages();
    ...
}

Class ProductRepo implements ProductRepositoryInterface{
    protected $productFactory;
    protected $imageFactory;
    public function __construct(ProductFactoryInterface $productFactory, ImageFactoryInterface $imageFactory)
    {
        $this->productFactory = $productFactory;
        $this->imageFactory = $imageFactory;
    }

    public function findAll(...)
    {
        $result = $this->execute('....');
        $products = $this->productFactory->make($result);
        return $products;
    }

    public function getImages($productId)
    {
        $result = $this->execute('....');
        $images = $this->imageFactory->make($result);
        return $images;
    }
}

Class ProductFactory implements ProductFactoryInterface{
    protected $productRepo;
    public function __construct(ProductRepositoryInterface $productRepo)
    {
        $this->productRepo = $productRepo;
    }

    public function make($items)
    {
        ...
        $products = [];
        foreach($items as $item){
            $product = new Product($item);
            $item->setImages($this->productRepo->getImages($product->getId()));
            $products[] = $product;
        }
        ...
        return $products;
    }
}

Class ImageFactory implements ImageFactoryInterface{
    public function make($items)
    {
        ...
        $images = [];
        foreach($items as $item){
            $image = new Image($item);
            $images[] = $image;
        }
        ...
        return $images;
    }
}

所以,我遇到了以下问题:

  1. 循环依赖 ProductRepo --> ProductFactory --> ProductRepo

    要跳过这个,我可以使用 setter 注入或使用代理模式。但我认为这不是一个好的解决方案。你们是怎么处理这类问题的?

  2. ProductRepo 依赖于 ProductFactory 和 ImageFactory。依赖多个工厂是一种好习惯吗?

我觉得问题很清楚。 :) 谢谢

据我所知,你不需要工厂模式来处理你正在做的事情,而不是不同类型的图像和产品 classes,你只有一种产品 class不同的细节。

我建议创建一个单一的产品 class 使用构造函数从产品数据库接收单行信息和属于它的图像集合。然后构造函数可以设置产品 class.

然后,在产品库 class 和 return 中创建一个产品集合或数组。

类似这样的东西(写成伪php)

    Class Product
    {
        public function __construct(productInfo, imageArray)
        {
            //contruct product here
        }
    }

    Class ProductRepo
    {

        public function getProducts()
        {
            //retrieve products
            $items = getProducts();

            //setup products
            return setupProducts($items);
        }

        private function setupProducts($items)
        {

            foreach($items as $item){
                $images = $this->getImages($product->getId());

                $product = new Product($item, $images);

                $products[] = $product;
        }
            return $products;
        }

        private function getImages($itemId)
        {
            //get and return images for this product
        }

        private function loadProducts()
        {
            //load from database and return all products
        }
    }

工厂模式适用于您需要在具体对象中实现具有不同功能的接口的多个实现,并且您需要一种方法来 select 正确的方法。例如,如果您有一个试图计算各种形状面积的应用程序,您可能有一个带有 calculateArea() 函数的 IShapes 接口和几个实现它的 classes(例如,Circle、Triangle、矩形等)都使用不同的公式来计算形状的面积。然后,您可以使用工厂为一组通用参数构造和获取特定形状名称的正确实现。

编辑: 如果不同产品类型在功能上有所不同,比如奖励积分的计算方式,您可以这样做:

    class ProductFactory
    {
        public Iproduct getProduct($productType, $productInfo, $images)
        {
            switch(productType)
            {
                case: featured
                    return new featuredProduct($productInfo)
                case: standard
                    return new standardProduct($productInfo)
            }
        }
    }

    Interface Iproducts
    {
        //suppose different product types have different reward point formula's
        calculateRewardPoints();

        ....
        //other functions
    }

然后可以像这样在上面的产品回购中使用它:

    private function setupProducts($items)
    {
        foreach($items as $item){
        $images = $this->getImages($product->getId());

            $product = ProductFactory.getProduct($item.type, $item, $images);

            $products[] = $product;
    }

有几种方法可以打破循环依赖,但最根本的问题似乎是 ProductFactory 需要一个 ProductRepo,它本身必须能够构建产品,即使这个功能不会被使用而且它可能不会传递使用不同工厂的 ProductRepo 是有意义的(隐藏规则)。所以:

1) 创建一个只有 getImages 方法的 ImageRepositoryInterface。 ProductRepositoryInterface 可以扩展此接口,也可以 ProductRepo 独立实现它。然后,将图像存储库传递到 ProductFactoryInterface.make 而不是在构造时要求它。你这时候可以通过你的ProductRepo。

2) 是的,依赖不止一种工厂是没有问题的