工厂方法与DI和IOC [英] Factory method with DI and Ioc

查看:93
本文介绍了工厂方法与DI和IOC的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我熟悉这些模式,但仍然不知道如何处理以下情况:

 公共类CarFactory
{
     公共CarFactory(DEP1,Dep2,Dep3,Dep4,Dep5,Dep6)
     {     }     公共ICAR CreateCar(类型)
     {
            开关(类型)
            {
               方案A:
                   返回新的分享帮助(DEP1,Dep2,Dep3);
               打破;               情况B:
                   返回新CAR2(Dep4,Dep5,Dep6);
               打破;
            }
     }
}

在一般的问题是与需要被注入的引用的量。当有更多的汽车会更差。

这在我脑海中第一种方法是注射分享帮助和CAR2工厂构造函数,但它是针对工厂的方法,因为工厂将始终返回相同的对象。第二种方法是注射服务定位,但它的反模式无处不在。如何解决呢?

编辑:

替代方法1:

 公共类CarFactory
{
     公共CarFactory(集装箱的IContainer)
     {
        _container =容器;
     }     公共ICAR CreateCar(类型)
     {
            开关(类型)
            {
               方案A:
                   返回_container.Resolve< ICar1>();
               打破;               情况B:
                     返回_container.Resolve< ICar2>();
               打破;
            }
     }
}

办法替代2(因为太多的树的依赖关系太难用了):

 公共类CarFactory
{
     公共CarFactory()
     {
     }     公共ICAR CreateCar(类型)
     {
            开关(类型)
            {
               方案A:
                   返回新的分享帮助(新DEP1(),新Dep2(新Dep683(),新Dep684()),....)
               打破;               情况B:
                    返回新CAR2(新Dep4(),新Dep5(新Dep777(),新Dep684()),....)
               打破;
            }
     }
}


解决方案

有一个工厂内的一个开关case语句是code气味。有趣的是,你似乎并不需要重点解决这个问题的。

最好的,最友好的DI为这种情况的解决方案是策略模式。它可以让你的DI容器注入的依赖到属于他们的地方工厂的情况下,不会搞乱其他类与那些依赖或求助于服务定位器。

接口

 公共接口ICarFactory
{
    ICAR CreateCar();
    布尔AppliesTo(类型类型);
}公共接口ICarStrategy
{
    ICAR CreateCar(类型类型);
}

工厂

 公共类Car1Factory:ICarFactory
{
    私人只读IDep1 DEP1;
    私人只读IDep2 dep2;
    私人只读IDep3 dep3;    公共Car1Factory(IDep1 DEP1,IDep2 dep2,IDep3 dep3)
    {
        如果(DEP1 == NULL)
            抛出新的ArgumentNullException(DEP1);
        如果(dep2 == NULL)
            抛出新的ArgumentNullException(dep2);
        如果(dep3 == NULL)
            抛出新的ArgumentNullException(dep3);        this.dep1 = DEP1;
        this.dep2 = dep2;
        this.dep3 = dep3;
    }    公共ICAR CreateCar()
    {
        返回新的分享帮助(this.dep1,this.dep2,this.dep3);
    }    公共BOOL AppliesTo(类型类型)
    {
        返回的typeof(分享帮助).Equals(类型);
    }
}公共类Car2Factory:ICarFactory
{
    私人只读IDep4 dep4;
    私人只读IDep5 dep5;
    私人只读IDep6 dep6;    公共Car1Factory(IDep4 dep4,IDep5 dep5,IDep6 dep6)
    {
        如果(dep4 == NULL)
            抛出新的ArgumentNullException(dep4);
        如果(dep5 == NULL)
            抛出新的ArgumentNullException(dep5);
        如果(dep6 == NULL)
            抛出新的ArgumentNullException(dep6);        this.dep4 = dep4;
        this.dep5​​ = dep5;
        this.dep6 = dep6;
    }    公共ICAR CreateCar()
    {
        返回新CAR2(this.dep4,this.dep5​​,this.dep6);
    }    公共BOOL AppliesTo(类型类型)
    {
        返回的typeof(CAR2).Equals(类型);
    }
}

策略

 公共类CarStrategy:ICarStrategy
{
    私人只读ICarFactory [] carFactories;    公共CarStrategy(ICarFactory [] carFactories)
    {
        如果(carFactories == NULL)
            抛出新的ArgumentNullException(carFactories);        this.carFactories = carFactories;
    }    公共ICAR CreateCar(类型类型)
    {
        VAR carFactory = this.carFactories
            .FirstOrDefault(出厂=> factory.AppliesTo(类型));        如果(carFactory == NULL)
        {
            抛出新的异常(类型未注册);
        }        返回carFactory.CreateCar();
    }
}

用法

  //我显示这code,但你通常会
//在你的作文与DI容器做到这一点
//根,和实例将通过注入创建
地方//它。
VAR战略=新CarStrategy(新ICarFactory [] {
    新Car1Factory(DEP1,dep2,dep3)
    新Car2Factory(dep4,dep5,dep6)
    });//然后,一旦注入,您只需做到这一点。
//请注意,您可以使用一个特殊的字符串或其他一些
//数据类型,如果你preFER参数。
VAR CAR1 = strategy.CreateCar(typeof运算(分享帮助));
VAR CAR2 = strategy.CreateCar(typeof运算(CAR2));

请注意,由于没有开关case语句,可以向战略添加额外的工厂在不改变设计,而且每个工厂都可以有自己的依赖由该DI容器注入。

  VAR战略=新CarStrategy(新ICarFactory [] {
    新Car1Factory(DEP1,dep2,dep3)
    新Car2Factory(dep4,dep5,dep6)
    新Car3Factory(dep7,dep8,dep9)
    });VAR CAR1 = strategy.CreateCar(typeof运算(分享帮助));
VAR CAR2 = strategy.CreateCar(typeof运算(CAR2));
VAR car3 = strategy.CreateCar(typeof运算(Car3));

I am familiar with these patterns but still don't know how to handle following situation:

public class CarFactory
{
     public CarFactory(Dep1,Dep2,Dep3,Dep4,Dep5,Dep6)
     {

     }

     public ICar CreateCar(type)
     {
            switch(type)
            {
               case A:
                   return new Car1(Dep1,Dep2,Dep3);
               break;

               case B:
                   return new Car2(Dep4,Dep5,Dep6);
               break;
            }
     }
}

In general the problem is with amount of references that needs to be injected. It will be even worse when there are more cars.

First approach that comes to my mind is to inject Car1 and Car2 in factory constructor but it is against factory approach because factory will return always the same object. The second approach is to inject servicelocator but it's antipattern everywhere. How to solve it?

Edit:

Alternative way 1:

public class CarFactory
{
     public CarFactory(IContainer container)
     {
        _container = container;
     }

     public ICar CreateCar(type)
     {
            switch(type)
            {
               case A:
                   return _container.Resolve<ICar1>();
               break;

               case B:
                     return _container.Resolve<ICar2>();
               break;
            }
     }
}

Alternative way 2 (too hard to use because of too many of dependencies in tree):

public class CarFactory
{
     public CarFactory()
     {
     }

     public ICar CreateCar(type)
     {
            switch(type)
            {
               case A:
                   return new Car1(new Dep1(),new Dep2(new Dep683(),new Dep684()),....)
               break;

               case B:
                    return new Car2(new Dep4(),new Dep5(new Dep777(),new Dep684()),....)
               break;
            }
     }
}

解决方案

Having a switch case statement inside of a factory is a code smell. Interestingly, you don't seem to be focusing on solving that issue at all.

The best, most DI friendly solution for this scenario is the strategy pattern. It allows your DI container to inject the dependencies into the factory instances where they belong, without cluttering up other classes with those dependencies or resorting to a service locator.

Interfaces

public interface ICarFactory
{
    ICar CreateCar();
    bool AppliesTo(Type type);
}

public interface ICarStrategy
{
    ICar CreateCar(Type type);
}

Factories

public class Car1Factory : ICarFactory
{
    private readonly IDep1 dep1;
    private readonly IDep2 dep2;
    private readonly IDep3 dep3;

    public Car1Factory(IDep1 dep1, IDep2 dep2, IDep3 dep3)
    {
        if (dep1 == null)
            throw new ArgumentNullException("dep1");
        if (dep2 == null)
            throw new ArgumentNullException("dep2");
        if (dep3 == null)
            throw new ArgumentNullException("dep3");

        this.dep1 = dep1;
        this.dep2 = dep2;
        this.dep3 = dep3;
    }

    public ICar CreateCar()
    {
        return new Car1(this.dep1, this.dep2, this.dep3);
    }

    public bool AppliesTo(Type type)
    {
        return typeof(Car1).Equals(type);
    }
}

public class Car2Factory : ICarFactory
{
    private readonly IDep4 dep4;
    private readonly IDep5 dep5;
    private readonly IDep6 dep6;

    public Car1Factory(IDep4 dep4, IDep5 dep5, IDep6 dep6)
    {
        if (dep4 == null)
            throw new ArgumentNullException("dep4");
        if (dep5 == null)
            throw new ArgumentNullException("dep5");
        if (dep6 == null)
            throw new ArgumentNullException("dep6");

        this.dep4 = dep4;
        this.dep5 = dep5;
        this.dep6 = dep6;
    }

    public ICar CreateCar()
    {
        return new Car2(this.dep4, this.dep5, this.dep6);
    }

    public bool AppliesTo(Type type)
    {
        return typeof(Car2).Equals(type);
    }
}

Strategy

public class CarStrategy : ICarStrategy
{
    private readonly ICarFactory[] carFactories;

    public CarStrategy(ICarFactory[] carFactories)
    {
        if (carFactories == null)
            throw new ArgumentNullException("carFactories");

        this.carFactories = carFactories;
    }

    public ICar CreateCar(Type type)
    {
        var carFactory = this.carFactories
            .FirstOrDefault(factory => factory.AppliesTo(type));

        if (carFactory == null)
        {
            throw new Exception("type not registered");
        }

        return carFactory.CreateCar();
    }
}

Usage

// I am showing this in code, but you would normally 
// do this with your DI container in your composition 
// root, and the instance would be created by injecting 
// it somewhere.
var strategy = new CarStrategy(new ICarFactory[] {
    new Car1Factory(dep1, dep2, dep3),
    new Car2Factory(dep4, dep5, dep6)
    });

// And then once it is injected, you would simply do this.
// Note that you could use a magic string or some other 
// data type as the parameter if you prefer.
var car1 = strategy.CreateCar(typeof(Car1));
var car2 = strategy.CreateCar(typeof(Car2));

Note that because there is no switch case statement, you can add additional factories to the strategy without changing the design, and each of those factories can have their own dependencies that are injected by the DI container.

var strategy = new CarStrategy(new ICarFactory[] {
    new Car1Factory(dep1, dep2, dep3),
    new Car2Factory(dep4, dep5, dep6),
    new Car3Factory(dep7, dep8, dep9)
    });

var car1 = strategy.CreateCar(typeof(Car1));
var car2 = strategy.CreateCar(typeof(Car2));
var car3 = strategy.CreateCar(typeof(Car3));

这篇关于工厂方法与DI和IOC的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆