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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/database/10.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
C# 当一个简单的依赖注入已经足够时,为什么要使用工厂模式_C#_Design Patterns_Dependency Injection_Factory Pattern - Fatal编程技术网

C# 当一个简单的依赖注入已经足够时,为什么要使用工厂模式

C# 当一个简单的依赖注入已经足够时,为什么要使用工厂模式,c#,design-patterns,dependency-injection,factory-pattern,C#,Design Patterns,Dependency Injection,Factory Pattern,我期待着了解工厂模式的使用 我是这个领域的爱好者,所以请原谅我的愚蠢问题 我的问题是,我看不到工厂模式的使用,它返回给我们接口,我们可以在需要时直接注入它 在上面的例子中,我会这样做: public class Program { // register the interfaces with DI container in a separate config class (Unity in this case) private readonly IShippingStrateg

我期待着了解工厂模式的使用

我是这个领域的爱好者,所以请原谅我的愚蠢问题

我的问题是,我看不到工厂模式的使用,它返回给我们接口,我们可以在需要时直接注入它

在上面的例子中,我会这样做:

public class Program
{
    // register the interfaces with DI container in a separate config class (Unity in this case)
    private readonly IShippingStrategy _shippingStrategy;

    public Program(IShippingStrategy shippingStrategy)
    {
        _shippingStrategy= shippingStrategy;
    }

    public int DoTheWork(Order order)
    {
        // assign properties just as an example
        order.ShippingMethod = "Fedex";
        order.OrderTotal = 90;
        order.OrderWeight = 12;
        order.OrderZipCode = 98109;

        int shippingCost = _shippingStrategy.CalculateShippingCost(order);

        return shippingCost;
    }
}
而不是注入工厂:

public class Program
{
    // register the interfaces with DI container in a separate config class (Unity in this case)
    private readonly IShippingStrategyFactory _shippingStrategyFactory;

    public Program(IShippingStrategyFactory shippingStrategyFactory)
    {
        _shippingStrategyFactory = shippingStrategyFactory;
    }

    public int DoTheWork(Order order)
    {
        // assign properties just as an example
        order.ShippingMethod = "Fedex";
        order.OrderTotal = 90;
        order.OrderWeight = 12;
        order.OrderZipCode = 98109;

        IShippingStrategy shippingStrategy = _shippingStrategyFactory.GetShippingStrategy(order);
        int shippingCost = shippingStrategy.CalculateShippingCost(order);

        return shippingCost;
    }
}

当我们可以将接口直接注入到需要使用它的任何地方时,为什么要使用bruden创建工厂(从而添加一个额外的层)?

如果您检查工厂的代码,您可以看到,根据订单的发货方法,工厂会返回不同的IShippingStrategy实现。由于ShippingMethod只在调用DoTheWork后才被知道,因此在构建类时不可能注入正确的实现(同一个类甚至可能需要不同的实现来满足不同的顺序)

我想你不需要再写一篇关于工厂模式的文章,而需要一个简短全面的答案。 所以,我想集中讨论两件事

更灵活 最常见的是,你会在你基本上说

“如果任何人想要
IAnyService
,他应该获得
MyAnyServiceImplementation

这是为您的应用程序修复的。设置之后,依赖项注入容器将为您注册的类实例提供服务,但您不应再次尝试重新配置该容器。这非常适合于启动灵活性,例如通过应用程序的配置注册数据访问组件的实现。说

“如果任何人想要
IUserRepository
,他应该获得
MsSqlUserRepository
,因为我们正在使用MSSQL服务器”

当然,拥有“不可变”的组合根限制了根据应用程序的状态在运行时选择实现的可能性

相反,您可以注入一个类,该类根据当前状态决定选择哪个服务实现。数据验证是该模式的典型场景,因为系统上的不同实体可能有不同的规则。这里的流行语是“规则模式”或“策略模式”

寿命控制 考虑一个长期存在的类实例,比如视图(用户界面)或任何附加到它的类(比如viewmodel或控制器)。只要用户在视图上处于活动状态,该类就处于活动状态。例如,通过向视图控制器的构造函数注入一个类实例,只要视图存在,就可以保持它的一个活动实例

例如,假设您希望使用数据存储库连接到数据库。这些数据库访问调用应该很短,并且您不希望长时间保持连接打开。使用存储库工厂,您可以非常精确地控制生存期,并确保类在使用后被删除:

using (var repository = new _factory.CreateRepository(...))
{
    return repository.GetAnything();
}
有了这个,一个非常轻量级的类——工厂——被注入,并且与视图控制器的寿命一样长。重类——连接的东西——不应该存在很长时间,只在需要时创建


事实上,如果不需要加载数据(例如,由于前端缓存命中),则存储库可能根本就没有实例化。如果您将直接注入存储库,您将保证在每种情况下都有一个长期存在的实例存在于内存中。

请解释如何使注入的装运策略依赖于订单,从参数到工厂方法可以明显看出。依赖项注入是一个通用概念,通常,DI是通过使用DI框架来完成的,它本质上只是一个通用的工厂模式,允许非常灵活的配置工具。因此,本质上,DI框架是一个工厂。但并非所有工厂都是DI框架。通常,一个工厂指的是定制工厂,针对特定情况进行定制。一些DI框架甚至允许您指定自定义工厂来更精细地控制逻辑。因此,简而言之,当我们不知道在使用工厂模式时使用哪个接口实现时,我们使用工厂模式?我认为,当直接注入接口时,我们还应该指出(在另一个地方使用哪个实现),但我想这是错误的,如果您可以将服务绑定到特定的依赖项,您通常可以使用注册,在这种情况下,您可以使用DI。但是,如果正确的服务取决于所涉及的数据,那么工厂模式就是最好的选择。太好了!我从来不知道在DI中有一种叫做注册的东西。非常感谢你!很好的解释。我只想强调一下你在“更灵活”一节中说的话。假设我有您提到的
IUserRepository
接口。对我来说,使用工厂模式的优势在于,我们能够在同一个应用程序中使用各种数据访问组件。例如,如果我们有
MsSqlUserRepository
AzurelUserRepository
我们可以在同一个应用程序中使用它们,使用工厂模式,这是不可能的,如果我们直接注入
IUserRepository
对吗?Mmmh。。。不完全是。你也可以在没有工厂的情况下使用它们。但是,您只能在应用程序启动时做出一次决定。如果配置为使用MSSQL,请使用
MSSQLSUserRepository
;如果配置为与Azure同步,请使用
AzureUserRepository
。一旦流程运行,您就必须接受它。拥有一个工厂可以让您在运行时在这两者之间切换,但我认为数据访问不是它的最佳用例,因为它不太可能是通用的。也许你的意思是一样的,我不确定我是否“在同一个应用程序中”正确。非常好