为什么在简单的依赖注入就足够时使用工厂模式
Why using the factory pattern when a simple dependecy injection is enough
我正在寻找这个 来了解工厂模式的使用。
我真的是这个领域的爱好者所以请原谅我的愚蠢问题。
我的问题是我没有看到工厂模式的使用return我们可以在需要使用时直接注入的接口。
在上面的例子中我会做这样的事情:
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;
}
}
当我们可以将接口直接注入到我们需要使用它的任何地方时,为什么还要花时间创建一个工厂(从而增加一个额外的层)?
如果您检查工厂的代码,您会发现根据订单的 ShippingMethod,工厂返回 IShippingStrategy 的不同实现。由于仅在调用 DoTheWork 后才知道 ShippingMethod,因此在构造 class 时不可能注入正确的实现(并且相同的 class 甚至可能需要针对不同订单的不同实现)。
我认为您不想要另一篇关于工厂模式的文章,而是一个简短而全面的答案。
所以,我想关注两件事。
更大的灵活性
最常见的是,你会在你基本上说的地方设置你的组合根...
"if anyone wants IAnyService
, he should get MyAnyServiceImplementation
".
这是针对您的应用程序修复的。设置完成后,您的依赖项注入容器将为您注册的 class 个实例提供服务,但您不应再次尝试重新配置该容器。这非常适合启动灵活性,例如通过应用程序的配置注册数据访问组件的实现。说...
"if anyone wants IUserRepository
, he should get MsSqlUserRepository
because we are working with MSSQL server".
当然,"immutable" 组合根限制了根据应用程序的状态在运行时选择实现的可能性。
相反,您可以注入一个 class 来决定当前状态选择哪个服务实现。数据验证是该模式的典型场景,因为系统上的不同实体可能有不同的规则。这里的流行语是 "rule pattern" 或 "strategy pattern".
终身掌控
将长期存在的 class 实例想象成视图(用户界面)或附加到它的任何 class(如视图模型或控制器)。只要用户在视图上处于活动状态,class 就存在。例如,通过将 class 实例注入视图控制器的构造函数,只要视图存在,您就持有它的活动实例。
假设您想使用数据存储库连接到数据库。这些数据库访问调用应该很短,您不希望长时间保持连接打开。使用存储库工厂,您可以非常精确地控制生命周期并确保 class 在使用后被删除:
using (var repository = new _factory.CreateRepository(...))
{
return repository.GetAnything();
}
有了这个,一个非常轻量级的 class - 工厂 - 被注入并且只要视图控制器存在就存在。繁重的 classes - 连接的东西 - 不应该存在很长时间并且只在需要时创建。
事实上,如果不需要加载数据(例如,由于前期缓存命中),则可能根本不会实例化存储库。如果您直接注入存储库,则可以保证在每种情况下都有一个长期存在的实例存在于内存中。
我正在寻找这个
我真的是这个领域的爱好者所以请原谅我的愚蠢问题。
我的问题是我没有看到工厂模式的使用return我们可以在需要使用时直接注入的接口。
在上面的例子中我会做这样的事情:
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;
}
}
当我们可以将接口直接注入到我们需要使用它的任何地方时,为什么还要花时间创建一个工厂(从而增加一个额外的层)?
如果您检查工厂的代码,您会发现根据订单的 ShippingMethod,工厂返回 IShippingStrategy 的不同实现。由于仅在调用 DoTheWork 后才知道 ShippingMethod,因此在构造 class 时不可能注入正确的实现(并且相同的 class 甚至可能需要针对不同订单的不同实现)。
我认为您不想要另一篇关于工厂模式的文章,而是一个简短而全面的答案。 所以,我想关注两件事。
更大的灵活性
最常见的是,你会在你基本上说的地方设置你的组合根...
"if anyone wants
IAnyService
, he should getMyAnyServiceImplementation
".
这是针对您的应用程序修复的。设置完成后,您的依赖项注入容器将为您注册的 class 个实例提供服务,但您不应再次尝试重新配置该容器。这非常适合启动灵活性,例如通过应用程序的配置注册数据访问组件的实现。说...
"if anyone wants
IUserRepository
, he should getMsSqlUserRepository
because we are working with MSSQL server".
当然,"immutable" 组合根限制了根据应用程序的状态在运行时选择实现的可能性。
相反,您可以注入一个 class 来决定当前状态选择哪个服务实现。数据验证是该模式的典型场景,因为系统上的不同实体可能有不同的规则。这里的流行语是 "rule pattern" 或 "strategy pattern".
终身掌控
将长期存在的 class 实例想象成视图(用户界面)或附加到它的任何 class(如视图模型或控制器)。只要用户在视图上处于活动状态,class 就存在。例如,通过将 class 实例注入视图控制器的构造函数,只要视图存在,您就持有它的活动实例。
假设您想使用数据存储库连接到数据库。这些数据库访问调用应该很短,您不希望长时间保持连接打开。使用存储库工厂,您可以非常精确地控制生命周期并确保 class 在使用后被删除:
using (var repository = new _factory.CreateRepository(...))
{
return repository.GetAnything();
}
有了这个,一个非常轻量级的 class - 工厂 - 被注入并且只要视图控制器存在就存在。繁重的 classes - 连接的东西 - 不应该存在很长时间并且只在需要时创建。
事实上,如果不需要加载数据(例如,由于前期缓存命中),则可能根本不会实例化存储库。如果您直接注入存储库,则可以保证在每种情况下都有一个长期存在的实例存在于内存中。