我正在为业务对象编写一个框架。由于以下原因,我大量使用接口:
1)自动内存管理
2)关注点分离
通常构造函数有一些参数是框架的对象,但我不能将它们放在接口中。
我的问题是,如果我使用接口来分离实现它们的类的关注,为什么我的代码最终仍然绑定到实现接口的具体类来调用构造函数及其参数。和
将创建者代码放入工厂方法的优点是什么? (我还没有使用的东西..)
谢谢!
===编辑===
我的问题中的一点是构造函数的参数..在框架中很多对象需要一些其他的工作..答案很好地解决了关注点,但我仍然看不出如何解决参数问题..
如果我不采用构造函数的方式,我应该在对象的每个方法中使用“过程初始化”方式(在界面中)和“CheckObjectInitialized”(受保护)。这将如何更干净?
答案 0 :(得分:8)
Factory方法允许您在一个地方注册接口的实现者,并允许其余代码“只需要一个实现者。”
Factory.GetImplementorOf(IMyInterface)
然后返回一个接口引用。
由您决定如何实施工厂。您可以为所请求的每个接口创建新实例,维护已创建实例的池并返回对这些实例的引用,或根据请求的接口进行混合。
您还可以决定是否希望工厂允许同一接口的多个实现者(如何选择正确的接口)或为每个接口或混合强制实施单个实现者。
多个实例可以派上用场,例如在处理可能无法使用的重复(d)服务时,您可以选择一个恰好正常的服务。
提供GetImplementorOf(接口数组)可能也是一个想法。因此,您可以拥有IDump的多个实现者,但通过它们转储信息的方式区分它们:例如,IDump是IHTML格式的对象的实现者。
工厂准备在某些工作中使用构造函数参数 干净的方式??
那么现在,这是一个有趣的问题。不,他们自己也不是。工厂通常使用标准构造函数,可能采用“所有者”和/或“Id”参数。
如果你想在每个类的基础上有更多特定的构造函数,你必须
在某个阶段,我选择了第三个选项。通过创建
工厂TFactory = class(...) public procedure RegisterInterface(const aGUID: TGUID; const aAbstractBase: TClass); procedure RegisterImplementor(const aGUID: TGUID; const aImplementor: TClass); function GetImplementor(const aGUID: TGUID): TClass;
缺点:
总而言之,我已经回到标准构造函数/特定的Initialization对方法。编写代码扫描单元测试以检查来自工厂的每个GetImplementor调用是否跟随初始化调用应该相当容易。尽管理论上的类不再像使用特定构造函数那样不可变,但它仍然适用于所有实际目的。如果你想确保只在构造之后立即调用Initialize方法,那么应该很容易添加。
答案 1 :(得分:3)
接口不会消除实现对象的需要。您使用的每个接口都必须具有实现对象。所以你的代码需要调用构造函数。
工厂模式和其他创建模式允许您使对象创建更加灵活和模块化。这些创建模式允许您隐藏所有实现类声明,例如把它们放在单位的实施部分。
不使用方法来抽象界面创建,你的目标没有。 2将不完整。
答案 2 :(得分:3)
如果您觉得需要在接口上添加构造函数,那么您做错了。
接口只是功能声明。如何提供该功能与接口无关。实际上,如何创建实现对象应该完全不关心接口的使用者。这就是依赖注入的用武之地。
依赖注入是指接口的实现与实际使用接口的代码完全分离的概念。它不仅仅是一个工厂类(由Marjan巧妙地描述),因为它允许您从接口中完全解耦实现类的声明和实现。
因此,当您声明一个接口时,依赖注入容器可以自动创建/获取已实现对象的实例,从而无需您创建它。通过这种方式,您的应用程序变得只是接口连接在一起,而不用担心构造任何东西。您的库代码仅通过DI容器显示。
Delphi Spring Framework提供了一个非常好用的DI容器供您使用。你可以在这里找到Delphi Spring Framework和Spring Container:
答案 3 :(得分:1)
Nick Hodges presentation at CodeRage简单地说,你应该将建筑工作转移到一个由其自己负责创建对象的类。这通常被称为“工厂”模式。
从逻辑的角度来看,这对我来说是有意义的,因为它是SOLID原则中'S'的特定实例;单一责任。对象的创建应该是一个单一的责任(工厂),将对象链接在一起以解决问题(一个真实对象的组合加上五个模拟的,将是单元测试,或五个真实对象的组合来解决一个问题生产代码库中的问题。)