首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >基于DI和IoC的工厂方法

基于DI和IoC的工厂方法
EN

Stack Overflow用户
提问于 2015-08-11 19:31:11
回答 6查看 55.1K关注 0票数 59

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

代码语言:javascript
运行
复制
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;
            }
     }
}

一般来说,问题在于需要注入的引用量。如果有更多的汽车,情况会更糟。

我想到的第一种方法是在工厂构造函数中注入Car1和Car2,但这与工厂方法背道而驰,因为工厂总是返回相同的对象。第二种方法是注入servicelocator,但它到处都是反模式的。如何解决这个问题?

编辑:

备选办法1:

代码语言:javascript
运行
复制
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;
            }
     }
}

可供选择的方法2(由于树中的依赖关系太多而难以使用):

代码语言:javascript
运行
复制
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;
            }
     }
}
EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2015-08-12 17:24:38

在工厂内部有一个开关箱语句是一种代码气味。有趣的是,你似乎根本没有专注于解决这个问题。

对于这个场景,最好的、最友好的DI解决方案是战略模式。它允许您的DI容器将依赖项注入到它们所属的工厂实例中,而无需将其他类与这些依赖项混淆起来,也不需要求助于服务定位器。

接口

代码语言:javascript
运行
复制
public interface ICarFactory
{
    ICar CreateCar();
    bool AppliesTo(Type type);
}

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

工厂

代码语言:javascript
运行
复制
public class Car1Factory : ICarFactory
{
    private readonly IDep1 dep1;
    private readonly IDep2 dep2;
    private readonly IDep3 dep3;
    
    public Car1Factory(IDep1 dep1, IDep2 dep2, IDep3 dep3)
    {
        this.dep1 = dep1 ?? throw new ArgumentNullException(nameof(dep1));
        this.dep2 = dep2 ?? throw new ArgumentNullException(nameof(dep2));
        this.dep3 = dep3 ?? throw new ArgumentNullException(nameof(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 Car2Factory(IDep4 dep4, IDep5 dep5, IDep6 dep6)
    {
        this.dep4 = dep4 ?? throw new ArgumentNullException(nameof(dep4));
        this.dep5 = dep5 ?? throw new ArgumentNullException(nameof(dep5));
        this.dep6 = dep6 ?? throw new ArgumentNullException(nameof(dep6));
    }
    
    public ICar CreateCar()
    {
        return new Car2(this.dep4, this.dep5, this.dep6);
    }
    
    public bool AppliesTo(Type type)
    {
        return typeof(Car2).Equals(type);
    }
}

策略

代码语言:javascript
运行
复制
public class CarStrategy : ICarStrategy
{
    private readonly ICarFactory[] carFactories;

    public CarStrategy(ICarFactory[] carFactories)
    {
        this.carFactories = carFactories ?? throw new ArgumentNullException(nameof(carFactories));
    }
    
    public ICar CreateCar(Type type)
    {
        var carFactory = this.carFactories
            .FirstOrDefault(factory => factory.AppliesTo(type));
            
        if (carFactory == null)
        {
            throw new InvalidOperationException($"{type} not registered");
        }
        
        return carFactory.CreateCar();
    }
}

用法

代码语言:javascript
运行
复制
// 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));

注意,因为没有switch语句,所以您可以在不改变设计的情况下向策略中添加额外的工厂,并且每个工厂都可以有自己的依赖项,由DI容器注入。

代码语言:javascript
运行
复制
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));
票数 100
EN

Stack Overflow用户

发布于 2015-08-12 05:38:25

Composition Root回答您对代码示例的评论。您可以创建以下内容,但这不是服务定位器。

代码语言:javascript
运行
复制
public class CarFactory
{
    private readonly Func<Type, ICar> carFactory;

    public CarFactory(Func<Type, ICar> carFactory)
    {
       this.carFactory = carFactory;
    }

    public ICar CreateCar(Type carType)
    {
        return carFactory(carType);
 }

以下是使用Unity容器查看Composition Root的方式:

代码语言:javascript
运行
复制
Func<Type, ICar> carFactoryFunc = type => (ICar)container.Resolve(type);
container.RegisterInstance<CarFactory>(new CarFactory(carFactoryFunc));
票数 15
EN

Stack Overflow用户

发布于 2015-08-11 20:51:46

不久前,我回答了一个类似的问题。基本上都取决于你的选择。您必须在冗长(这给您更多来自编译器的帮助)和自动化之间进行选择,后者允许您编写更少的代码,但更容易出现错误。

是我支持冗长的答案。

也是一个很好的解决方案,它支持自动化。

编辑

我相信你认为错误的方法实际上是最好的。说实话,通常不会有,所以中有很多依赖项。我喜欢这种方法,因为它非常明确,很少导致运行时错误。

备选办法1:

这个很糟糕。它实际上是一个服务定位器,它被认为是一个反模式

备选方式2

正如您所写的,如果与IOC容器混合使用,则使用起来并不容易。然而,在某些情况下,类似的方法(可怜人的DI)可能是有用的。

总之,我不会在工厂中有“许多”依赖项。这是一个简单的声明性代码。它需要几秒钟的时间来编写,并且可以节省您在运行时错误中挣扎的时间。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/31950362

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档