如何使用组合而不是继承
本文关键字:继承 何使用 组合 | 更新日期: 2023-09-27 18:29:16
我有一个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不能从任何其他类继承??
我应该澄清一下,无论如何,Configurator必须实现IContextAware
接口。此外,该类必须有一个默认的/no-arg构造函数,因此构造函数依赖项注入在这里不是一个选项。
有人能建议如何使用Composition来实现同样的好处,但要有更灵活的设计,和/或描述上面继承解决方案的真正缺点吗?谢谢
附言:如果有人好奇的话,这是根据Spring.Net CodeConfig改编的。
我认为.NET基类库是一个很好的标准来回答这些问题。您对继承的使用永远不会被放入BCL中,因为它将API的用户暴露于API内部。现在有一个基类没有任何语义。它的存在只是为了保存代码。所有公共API元素都应该具有目的和语义。
在API设计方面,BCL的作者显然非常严格。我从未见过如此庞大而原始的类型收藏。
也就是说,如果你不需要API清洁度,你就不需要遵守同样的标准并不是每一个API都能接触到数以百万计的开发人员为了节省大量代码并消除冗余和潜在的错误,对API纯度进行一点妥协是合理的权衡。
我的选择:我会使用您的方法来编写内部代码。对于公共API(想想Codeplex库等等),我宁愿重复多余的东西,并保持公共API的表面清洁。