Oop 我应该使用继承吗?
这更像是一个主观问题,所以我要先把它标记为社区维基 基本上,我发现在我的大部分代码中,有许多类,其中许多类相互使用,但很少有类彼此直接相关。回顾我的大学时代,我想到了传统的猫:动物类的例子,你有巨大的继承树,但我在我的代码中没有看到这些。我的类图看起来像巨大的蜘蛛网,不像漂亮的树 我觉得我在逻辑上分离信息方面做得很好,最近我通过DI/IoC技术隔离了类之间的依赖关系,但我担心我可能遗漏了一些东西。我确实倾向于在接口中聚集行为,但我只是没有子类化 我可以很容易地理解传统示例中的子类化,例如Oop 我应该使用继承吗?,oop,inheritance,class-design,Oop,Inheritance,Class Design,这更像是一个主观问题,所以我要先把它标记为社区维基 基本上,我发现在我的大部分代码中,有许多类,其中许多类相互使用,但很少有类彼此直接相关。回顾我的大学时代,我想到了传统的猫:动物类的例子,你有巨大的继承树,但我在我的代码中没有看到这些。我的类图看起来像巨大的蜘蛛网,不像漂亮的树 我觉得我在逻辑上分离信息方面做得很好,最近我通过DI/IoC技术隔离了类之间的依赖关系,但我担心我可能遗漏了一些东西。我确实倾向于在接口中聚集行为,但我只是没有子类化 我可以很容易地理解传统示例中的子类化,例如类Dog
类Dog:Animal
或类Employee:Person
,但我没有任何明显的东西。而且事情很少像类标签:Control
那样清晰。但是,当涉及到在我的代码中将真实实体建模为层次结构时,我不知道从哪里开始
所以,我想我的问题可以归结为:
继承应始终表示“是一种”关系。如果A源于B,你应该能说“A是B”。如果不是,你更喜欢构图。当不需要子类时,不使用子类是完全可以的 例如,说
FileOpenDialog
是一个窗口
是有意义的,但说引擎
“是一辆汽车
是毫无意义的。在这种情况下,在汽车
实例中的发动机
实例更合适(可以说汽车
”是根据“发动机
”实现的)
有关继承的详细讨论,请参阅gotw.ca上的“继承的使用和滥用”
class X:Y{}
elseclass X{Y myY;}
或class Y{X myX;}
我也讨厌狗->哺乳动物->动物的例子,正是因为它们没有出现在现实生活中 我很少使用子类,因为它将子类与超类紧密地结合在一起,使您的代码很难阅读。有时实现继承很有用(例如PostgreSQLDatabaseImpl和MySQLDatabaseImpl扩展AbstractSQLDatabase),但大多数时候它只是把事情弄得一团糟。大多数时候,我看到子类的概念被误用,应该使用接口或属性 然而,接口是很好的,你应该使用它们。IMHO,你永远不应该这样做#3,除非你专门为此目的构建一个抽象基类,并且它的名称清楚地说明了它的用途:
class DataProviderBase {...}
class SqlDataProvider : DataProviderBase {...}
class DB2DataProvider : DataProviderBase {...}
class AccountDataProvider : SqlDataProvider {...}
class OrderDataProvider : SqlDataProvider {...}
class ShippingDataProvider : DB2DataProvider {...}
等等
同样遵循这种类型的模型,有时如果您提供一个接口(IDataProvider
),那么最好也提供一个基类(DataProviderBase
),未来的使用者可以使用它方便地访问应用程序模型中所有/大多数数据提供者通用的逻辑
不过,作为一般规则,只有在我拥有真正的“is-a”关系时,或者如果创建“is-a”关系(例如提供者模型)可以改善总体设计时,我才使用继承。任何技术或模式都不应该为了自身的目的而使用。显然,您工作的领域中的类往往无法从继承中获益,因此不应该使用继承 你用DI来保持东西整洁。你把你班上的事分开了。这些都是好事。如果你真的不需要继承,就不要试图强迫继承
这个问题的一个有趣的后续问题是:哪些编程领域倾向于很好地利用继承?(已经提到了UI和db框架,它们都是很好的例子。还有其他的吗?你的三个问题的答案都是“视情况而定”。最终,这一切都取决于您的域以及您的程序如何处理它。很多时候,我发现我选择使用的设计模式实际上有助于找到继承工作良好的地方 例如,考虑用一个“变压器”来将数据推入所需的形式。如果您将3个数据源作为CSV文件,并希望将它们放入三个不同的对象模型中(并可能将它们持久化到数据库中),则可以创建一个“CSV transformer”库,然后在继承时重写某些方法,以便处理不同的特定对象 将开发过程“转换”到模式语言中可以帮助您找到行为相似的对象/方法,并有助于减少冗余代码(可能通过继承,也可能通过使用共享库——以最适合的情况为准)
此外,如果将层(业务、数据、表示等)分开,类图将更简单,然后可以“可视化”那些无法继承的对象 在共享功能的地方,编程到接口比继承更重要 本质上,继承更多的是将对象关联在一起 大多数时候我们都很自负
class Product
class Article
class NewsItem
// A collection decorator that is-a collection with
public class MyCustomCollection implements java.util.Collection {
private Collection delegate;
// decorate methods with custom code
}