【问题标题】:interfaces and constructors in delphidelphi中的接口和构造函数
【发布时间】:2011-12-20 20:42:45
【问题描述】:

我正在为业务对象编写一个框架。我大量使用接口是因为:

1) 自动内存管理
2) 关注点分离

通常构造函数有一些参数是框架的对象,但我不能将它们放在接口中。

我的问题是,如果我使用接口来分离实现它们的类的关注点,为什么我的代码最终仍绑定到实现接口以调用构造函数及其参数的具体类..和

将创建者代码放入工厂方法有什么好处? (我还没有使用的东西..)

谢谢!

=== 编辑 ===

我的问题的重点是构造函数的参数。在框架中,许多对象需要其他一些才能工作。答案很好地解决了关注点分离的问题,但我仍然不明白如何解决参数问题..

如果我不采用构造方法,我应该在对象的每个方法中采用“过程初始化”方式(在接口中)和“CheckObjectInitialized”(受保护)。这样会更干净吗?

【问题讨论】:

  • 我要补充(3)单一责任原则,这实际上只是对第(2)点的重述,它使解耦设计成为可能。如果您有 (1) (2) (3),那么 Factory 显然是创建职责的单一责任“所有者”。
  • 您需要使用工厂或依赖注入。依赖注入是一种更现代的方法,但由于泛型,它需要 Delphi 2010 或更高版本。我的博客可能对工厂实现的基础知识有所帮助 - informativearchitecture.wordpress.com/2011/10/04/… 但您应该在此处查看 Nick Hodges 博客 goo.gl/u7GNb 以获得此类问题的理想解决方案。

标签: delphi interface constructor


【解决方案1】:

接口并没有消除实现对象的需要。您使用的每个接口都必须有一个实现对象。所以你的代码需要调用构造函数。

工厂模式和其他创建模式允许您使对象创建更加灵活和模块化。这些创建模式允许您隐藏所有实现类声明,例如将它们放在单元的实施部分。

不使用方法来抽象接口创建,你的目标没有。 2 将不完整。

【讨论】:

    【解决方案2】:

    Factory 方法将允许您在一个地方注册接口的实现者,并允许您的其余代码“只请求实现者”。

    Factory.GetImplementorOf(IMyInterface)
    

    然后返回一个接口引用。

    如何实现工厂由您决定。您可以为每个请求的接口创建新实例,维护一个已创建实例池并返回对这些实例的引用,或者根据请求的接口进行混合。

    您还可以决定是否希望您的工厂允许同一接口的多个实现者(然后如何选择正确的实现者)或为每个接口强制执行单个实现者,或混合使用。

    多个实例可以派上用场,例如在处理有时可能不可用的重复 (d) 服务时,您可以选择一个恰好启动的服务。

    提供一个GetImplementorOf(接口数组)也可能是一个想法。因此,您可以拥有多个 IDump 实现者,但通过它们转储信息的方式来区分它们:例如,IDump 的实现者是 IHTML 格式的对象。


    工厂是否准备在某些情况下使用构造函数参数 干净的方式??

    现在,这是一个有趣的问题。不,它们本身不是。工厂通常使用标准构造函数,可能带有“Owner”和/或“Id”参数。

    如果你想在每个类的基础上更具体的构造函数,你必须

    • 创建更多工厂,这违背了使用单点注册接口实现者的目的
    • 允许基于每个接口/类的初始化方法应在构造后立即调用,这会使您的代码容易遗忘并使类不那么不可变。
    • 或者想办法将构造函数签名知识整合到工厂中。

    在某个阶段,我选择了第三个选项。通过创建一个工厂

    • 需要使用抽象基类注册接口
    • 要求实现者从抽象基类继承
    • 将实现者作为元类引用而不是实例返回
    TFactory = 类(...) 民众 过程 RegisterInterface(const aGUID: TGUID; const aAbstractBase: TClass); 过程 RegisterImplementor(const aGUID: TGUID; const aImplementor: TClass); 函数 GetImplementor(const aGUID: TGUID): TClass;

    缺点:

    • 必须同时声明接口和抽象基类是一件很麻烦的事情。
    • 它破坏了单一继承语言中接口的“接口多重继承”优势。
    • 您需要在整个代码中传播接口/抽象基类对的知识,否则您仍然无法使用特定于类的构造函数。泛型在这里可能会有所帮助,但我还没有研究过。
    • 如果您没有相同(一组)接口的多个实现者,则它没有实际用途。
    • 即使您只需要多个实现者来进行单元测试,这似乎也有些矫枉过正。我发现在测试单元中声明的具有类接口相关部分的虚拟类更有帮助和更有效。

    总而言之,我回到了标准构造函数/特定的初始化对方法。编写代码扫描单元测试来检查工厂的每个 GetImplementor 调用是否都跟在 Initialization 调用之后应该相当容易。尽管理论上的类不再像使用特定构造函数那样不可变,但它仍然适用于所有实际目的。如果你想确保 Initialize 方法只在构造之后被调用,那应该很容易添加。

    【讨论】:

    • 我已经扩展了我的问题.. 工厂准备好以某种干净的方式使用构造函数参数了吗??
    【解决方案3】:

    Nick Hodges presentation at CodeRage 简单地说,您应该将构建工作转移到一个唯一负责创建对象的类。这通常被称为“工厂”模式。

    从逻辑的角度来看,作为 SOLID 原则中“S”的一个具体实例,这对我来说是有意义的;单一职责。对象的创建应该是一个单一的职责(工厂),将对象链接在一起以解决一个问题(一个真实对象加上五个模拟对象的组合,将是一个单元测试,或者五个真实对象的组合来解决一个真实的问题)生产代码库中的问题)。

    【讨论】:

    • 感谢您的插件,沃伦。 ;-)
    • 这是一个非常好的演示文稿!对于任何错过它的人,重播现在链接在答案上。
    【解决方案4】:

    如果您觉得需要向接口添加构造函数,那么您做错了。

    接口只是功能的声明。如何提供该功能与界面无关。实际上,如何创建实现对象应该与接口的使用者完全无关。这就是依赖注入的用武之地。

    依赖注入是指接口的实现与实际使用接口的代码完全分离。它不仅仅是一个工厂类(正如 Marjan 巧妙地描述的那样),它允许您将实现类的声明和实现与接口完全分离。

    因此,当您声明接口时,依赖注入容器可以自动创建/获取已实现对象的实例,甚至无需您创建它。通过这种方式,您的应用程序只是接口的连接,而无需关心任何东西的构造。您的库代码仅通过 DI 容器显示。

    Delphi Spring Framework 提供了一个非常好的 DI Container 供您使用。你可以在这里找到 Delphi Spring Framework 和 Spring Container:

    http://code.google.com/p/delphi-spring-framework/

    【讨论】:

      猜你喜欢
      • 2017-01-21
      • 1970-01-01
      • 1970-01-01
      • 2012-10-14
      • 2011-02-17
      • 2017-04-07
      • 1970-01-01
      • 2010-12-13
      • 1970-01-01
      相关资源
      最近更新 更多