我有一个场景,我认为我不是严格编码到接口。 让我们说我有一个界面(在某些程序集中)
public interface IFoo
{
void GetSomething();
void SaveSomething();
}
现在,我有一个实现(在其他一些程序集中)
public class FoodB : IFoo
{
public FoodB(Guid guid, IFoodBConfig config) //IFoodBConfig is defined in same library where FoodB exists
{
...
}
}
因此,基本上实现需要guid和config
现在,我有一个客户端(在其他一些程序集中)希望使用IFoo
,例如
public class Client
{
public Client(IFoo foo)
{
...
}
}
DIP说必须在组合根处提供实现,并且客户端不能实例化对象本身。好的很棒。
现在,组合根或IoC容器决定将FoodB
作为具体实例注入,但它没有#guid'的值。因为它仅在运行时期间可用。
所以,我们决定抽象工厂。
public abstract FooFactory
{
public abstract IFoo GetFoo(Guid guid, IFoodBConfig config);
}
现在,提出了几个问题
a)必须修改客户端构造函数以接受FooFactory
而不是IFoo
,这意味着客户端已经决定使用哪种实现。在我看来,这使软件紧密耦合
b)即使客户端构造函数被修改为接受FooFactory
,也必须将IFoodBConfig
具体提供给构造函数,现在这将使客户端引用存在FoodB
的库。
FooFactory
放在声明IFoo
的库中是不正确的,因为工厂与IFoo
无关。由于相同的原因,将FooFactory
放入FoodB
库也不正确
d)简单地使用抽象工厂意味着交换实现的灵活性已经消失,因为客户端的目录与FoodBFactory
绑定。
这种做法是不正确的还是我们必须忍受的一些限制?
答案 0 :(得分:3)
在这个问题中要解决几点。
FooFactory
不是Abstract Factory
的示例,至少是GoF术语。Abstract Factory
!=名为Factory的抽象类。a)正如@dbugger评论的那样,将客户端耦合到抽象类与耦合到接口没有区别。
b)可以使用FooBFactory
预先配置FooBConfig
实施或IoC容器。然后客户端只传递其运行时guid。
c)FooFactory
与IFoo
直接相关,因为其目的是返回IFoo
的实例。实际上,它的方法的返回类型是IFoo
。
如果您愿意将客户端连接到IoC容器,客户端可以直接将容器用作工厂,从而消除了额外的工厂接口。