我试图尽可能多地解耦实现和接口/抽象类,以便能够轻松切换实现。
我了解到可行的方法是依赖注入,但在使用整个框架之前,我想实现/理解该机制。
我还了解到实现依赖注入的一种方法是使用抽象工厂。
我正在尝试在以下代码中使用它们,但我不知道在哪里可以在客户端和实现之间实现更多的解耦。我想我可能无法正确理解/实现工厂设计模式来解决这个问题。
我们说我有:
一个映射器,它是一个通用接口:
public interface Mapper<A,B> { [mapper methods]}
实现此映射器接口的具体类:
JsonMapper implements Mapper<Json,ModelObject>{ [mapper methods implemented..] }
现在我想在第三个对象中使用映射器,例如:
OnlineRepo {
// reference to an interface (which is good I guess)
Mapper<Json, ModelObject> mMapper;
// constructor needs a concrete Mapper<Json, ModelObject>
OnlineRepo(Mapper<Json, ModelObject> jsonToModelMapper ){
mMapper = jsonToModelObject;
}
// other OnlineRepo methods using mMapper, get, upsert etc etc...
[...]
}
最后我的主要代码必须实现正确的具体类。 &lt; - 那是我不喜欢的。
main{
JsonMapper mapper = new JsonMapper(); // reference to concrete JsonMapper
OnlineRepo repo = new OnlineRepo(mapper); // inject concrete JsonMapper
}
工厂设计模式如何帮助我解耦这些物体?
OnlineRepository
不直接引用具体JsonMapper
,它仅引用摘要Mapper<Json, ModelObject>
。不是吗?
抽象工厂设计模式如何帮助我更多地解耦这些代码。
好像我总是需要在我的主程序中引用一个实现(如果不是JsonMapper的实现,JsonMapperFactory的实现?)。
为了更好地说明我没有看到这个的优点:
对此:
我希望能够在main(我的客户)中做到这一点:
Mapper<Json, ModelObject> = GenericMapperFactory.getMapper()
这将自动提供JsonMapper。
我也可以这样做
Mapper<xml, ModelObject> = GenericMapperFactory.getMapper()
并获得正确的具体对象。
我希望我的问题很清楚,如果没有,请不要犹豫告诉我,以便我可以继续努力。这些概念对我来说还不完全清楚,所以我很难写出明确的问题。
提前感谢您的帮助。 最好的,安东尼
答案 0 :(得分:1)
实例化具体对象的位置与创建的类耦合。在您的情况下,这是主要的。通过使用工厂模式,您可以将主要与Mapper接口的实现分离。你只知道工厂。现在再次对Mapper进行子类化并使用另一种Mapper不会影响您的main方法。
为了保护您的Main不受实现类的限制,我不建议使用工厂模式。 Main是您的程序启动的地方,因此负责创建一些对象并将它们组合在一起以引导您的应用程序。
在应用程序中动态创建对象或使用一些同时使用的对象时,应使用工厂(例如:窗口工厂(GUI))
如果您创建一个可以使用Qt或Cocoa GUI运行的应用程序,则必须确保框架之间的一致性。 QtFactory会创建QWidgets和表单,而CocoaFactory会创建CocoaWindows。应用程序的其余部分与使用的框架分离。如果你在main中安装一个QtFactory,你的Programm将使用Qt GUI运行,使用CocoaFactory它将是一个Cocoa GUI。这是抽象的工厂模式。它允许你交换实现类,而不用担心它们是否会混合(Cocoa窗口与QWidget)。
答案 1 :(得分:0)
关键点是否使用工厂,但是你应该使用依赖注入进行一些控制容器的反转。因此,您的存储库实例化将由整个容器完成,您将使代码与实现完全无关。
否则,如果您进行手动依赖注入,显然您需要手动实例化实现。
例如,使用具有依赖注入支持的控件容器的反转,您将注入您的存储库,并且您将自动获得映射器的工厂或抽象映射器:
public class WhoKnows
{
public WhoKnows(IOnlineRepository repo)
{
// repo will come up with its dependencies already loaded
// and its dependencies will also have their own dependencies already
// loaded in cascade...
}
}