【问题标题】:How to use Composition instead of Inheritance?如何使用组合而不是继承?
【发布时间】:2013-08-28 14:07:53
【问题描述】:

我有一个Configurator 类,为了完成它的工作,必须通过接口接收一个Context 对象:

public class Configurator : IContextAware
{
    private IContext _context;

    //property setter defined by the IContextAware interface
    public IContext Context { set { _context = value; } }

    //  use _context object in other methods here ...
}

我计划编写许多Configurator 类型,它们都需要以相同的方式初始化它们的_context 字段。我的第一个想法是“为什么不激怒互联网上的每个程序员并使用继承”?

public class ContextInitializer: IContextAware
{
    // field to hold the injected context
    protected IContext _context;

    //property setter defined by the IContextAware interface
    public IContext Context { set { _context = value; } }
}

public class Configurator : ContextInitializer
{
    //  use _context object here ...
}

这样,我编写的任何其他需要 Context 对象的类都可以直接从 ContextInitializer 继承,并立即使用 Context 对象。

优点:保证一致的初始化,没有分散注意力,每个类中的重复初始化代码

缺点:实现继承是邪恶的!,.. 嗯,Configurator 不能从任何其他类继承.. ??

我应该澄清一下,配置器必须以一种或另一种方式实现IContextAware 接口。此外,该类必须有一个默认/无参数构造函数,因此构造函数依赖注入在这里不是一个选项。

有人可以建议如何使用组合来实现相同的好处,但设计​​更灵活,和/或描述上述继承解决方案的真正缺点吗?谢谢!

附:这是改编自 Spring.Net CodeConfig,如果有人好奇的话。

【问题讨论】:

  • 继承是邪恶的?我错过了那份备忘录。
  • @Rik blogs.msdn.com/b/steverowe/archive/2008/04/28/… javaworld.com/javaworld/jw-08-2003/jw-0801-toolbox.html c2.com/cgi/wiki?ImplementationInheritanceIsEvil 事实上,如果我被问到“ConfiguratorContextInitializer 吗?我不得不说不,但使用 ContextInitalizer,因此表明继承在这里并不完全正确。
  • 绝对陈述总是是错误的。继承本身并不是邪恶的。这是一个工具。您可以使用锤子将钉子钉入墙壁或敲开某人的头骨。这就是你如何使用它,这可能是邪恶的。
  • 好的,所以滥用继承是邪恶的。明白了。
  • @user1467261 - 你是对的,Configurator 使用 ContextInitializer。那么为什么不将构造函数设为public Configurator(IContextInitializer contextInitializer) { // use contextInitializer }? (顺便说一句。如果您打算使用不同类型的上下文初始化器,我强烈建议您使用接口)- 一个很好的例子是在 wikipedia

标签: c# inheritance


【解决方案1】:

我认为 .NET 基类库是一个很好的标准来回答这些问题。您对继承的使用永远不会被放入 BCL,因为它会将您的 API 用户暴露给 API 内部。现在有一个没有任何语义含义的基类。它只是为了保存代码而存在。所有公共 API 元素都应该有目的和语义。

BCL 的作者在 API 设计方面显然非常严格。我从未见过如此庞大而原始的类型集合。

也就是说,如果您不需要该级别的 API 清洁度,则无需遵守相同的标准。 并非每个 API 都向数百万开发人员公开。在 API 纯度上稍作妥协以节省大量代码并消除冗余和潜在的错误。

我的选择:我会将您的方法用于内部代码。对于公共 API(想想 Codeplex 库等),我宁愿复制多余的东西并保持公共 API 表面干净。

【讨论】:

    猜你喜欢
    • 2015-02-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多