比inheritance更喜欢构图?

为什么喜欢组合而不是inheritance? 每种方法都有哪些折衷? 什么时候你应该selectinheritance而不是组合?

因为它比以后更容易/更容易修改,所以比inheritance更喜欢组合,但不要使用组合总是方法。 通过组合,使用dependency injection/设置器可以轻松地改变行为。 inheritance更为严格,因为大多数语言不允许你从多个types派生。 所以,一旦你从TypeA派生出来,鹅就会或多或less的被煮熟了。

我对以上的酸性testing是:

  • TypeB是否想要公开TypeA的完整接口(所有公共方法都不less于),这样TypeB就可以用在需要TypeA的地方? 表示inheritance

例如塞斯纳双翼飞机将会暴露飞机的完整界面,如果不是更多的话。 所以这使它适合从飞机中派生出来。

  • TypeB是否只需要TypeA公开的部分行为? 表示需要合成。

例如,一只鸟可能只需要一架飞机的飞行行为。 在这种情况下,将其作为接口/类/两者提取出来并使其成为这两个类的成员是有意义的。

更新:回到我的答案,现在看来,如果没有具体提到芭芭拉·利斯科夫的Liskov替代原则,这是一个“我应该inheritance这种types吗?

把遏制看成是一种关系。 一辆车“有一个”引擎,一个人“有一个”的名字等

把遗传看作是一种关系。 汽车是“车”,“人”是“哺乳动物”等

我不赞成这种方法。 我从史蒂夫·麦康奈尔 ( Steve McConnell ) 第6.3 版的“完整代码”(Code Complete)第二版中直接了解了这一点

如果你明白这个区别,那就更容易解释了。

程序代码

一个例子是没有使用类的PHP(特别是在PHP5之前)。 所有的逻辑都被编码成一组函数。 你可以包含其他文件,包含帮助函数等等,并通过在函数中传递数据来执行你的业务逻辑。 随着应用程序的增长,这可能非常难以pipe理。 PHP5试图通过提供更多面向对象的devise来解决这个问题。

遗产

这鼓励使用类。 inheritance是面向对象devise的三个原则之一(inheritance,多态,封装)。

class Person { String Title; String Name; Int Age } class Employee : Person { Int Salary; String Title; } 

这是工作中的inheritance。 员工“是”人或inheritance人。 所有的inheritance关系都是“是一个”关系。 员工还会从Person中隐藏Title属性,这意味着Employee.Title将为Employee而不是Person返回Title。

组成

构成比inheritance更受青睐。 说得很简单,你会有:

 class Person { String Title; String Name; Int Age; public Person(String title, String name, String age) { this.Title = title; this.Name = name; this.Age = age; } } class Employee { Int Salary; private Person person; public Employee(Person p, Int salary) { this.person = p; this.Salary = salary; } } Person johnny = new Person ("Mr.", "John", 25); Employee john = new Employee (johnny, 50000); 

构图通常是“拥有”或“使用”的关系。 Employee类有一个Person。 它不会从Personinheritance,而是将Person对象传递给它,这就是为什么它具有“Person”。

构成的inheritance

现在说你想创build一个pipe理器types,所以你最终:

 class Manager : Person, Employee { ... } 

这个例子可以正常工作,但是,如果Person和Employee都声明了Title ? Manager.Title应该返回“运营经理”还是“Mr.”? 在构图下,这个含糊不清的问题处理得更好:

 Class Manager { public Title; public Manager(Person p, Employee e) { this.Title = e.Title; } } 

pipe理器对象组成一个员工和一个人。 标题行为取自员工。 这种明确的组合消除了其他事情的歧义,你会遇到更less的错误。

由于inheritance提供了所有不可否认的好处,这里有一些缺点。

遗传的缺点:

  1. 您不能在运行时更改从超类inheritance的实现(显然是因为在编译时定义了inheritance)。
  2. inheritance公开了一个子类的父类的实现的细节,这就是为什么经常说inheritance破坏封装(从某种意义上说,你真的需要只关注接口而不是实现,所以通过子类再次使用并不总是首选)。
  3. inheritance提供的紧密耦合使得子类的实现与超类的实现紧密相关,父类实现中的任何更改都会强制子类发生更改。
  4. 过度的分类重用可能会使得inheritance栈非常深,也很混乱。

另一方面, 对象组合是在运行时通过对象获取对其他对象的引用来定义的。 在这种情况下,这些对象将永远无法到达对方的受保护数据(没有封装中断),并将被迫相互尊重对方的接口。 在这种情况下,实现依赖关系将比inheritance的情况下less很多。

另一个非常实用的理由是,偏好合成而不是inheritance,与你的领域模型有关,并将其映射到关系数据库。 将inheritance映射到SQL模型是非常困难的(最终会出现各种各样的解决方法,比如创build并不总是使用的列,使用视图等)。 有些ORML试图解决这个问题,但是它总是变得很复杂。 可以通过两个表之间的外键关系容易地对构图进行build模,但是inheritance要困难得多。

简而言之,我会同意“偏好构图而不是inheritance”,对我来说,听起来像“比可口可乐更喜欢马铃薯”。 有inheritance的地方和组成的地方。 你需要了解差异,那么这个问题就会消失。 对我来说,真正的意思是“如果你要inheritance – 再想一想,有可能你需要组合”。

当你想要吃东西的时候,你应该更喜欢马铃薯,而不是可口可乐,而当你想要喝马铃薯时,更喜欢马铃薯的可口可乐。

创build子类应该不仅仅是一种调用超类方法的简便方法。 当子类“is-a”在结构上和function上都是超类时,你应该使用inheritance,当它可以作为超类使用时,你将使用它。 如果不是这样的话 – 那不是inheritance,而是别的。 构图是当你的对象由另一个构成时,或者与它们有某种关系。

所以对于我来说,如果有人不知道他是否需要inheritance或组成,真正的问题是他不知道他是否想要喝酒或吃饭。 多想想你的问题领域,更好地理解它。

inheritance是非常诱人的,特别是来自程序性的土地,它往往看起来欺骗性的优雅。 我的意思是我需要做的就是将这一点function添加到其他类,对不对? 那么,其中一个问题就是

inheritance可能是你可以拥有的最差的联结forms

您的基类通过将实现细节以受保护成员的forms公开给子类来打破封装。 这会使你的系统变得僵硬脆弱。 然而,更为悲惨的是,新的小类带来了遗产连锁的一切包袱和意见。

文章“ inheritance是邪恶的:DataAnnotationsModelBinder史诗般的失败” ,在C#中演示了这个例子。 它显示了当组合应该被使用时如何使用inheritance,以及它如何被重构。

在Java或C#中,对象一旦实例化就不能改变它的types。

所以,如果你的对象需要作为一个不同的对象出现,或者根据一个对象的状态或条件而有不同的performance,那就使用Composition :参考State和Strategy Design Patterns。

如果对象需要具有相同的types,则使用inheritance或实现接口。

就我个人而言,我总是比较喜欢构图而不是inheritance。 没有程序上的问题,你可以用inheritance来解决,而你不能用组合来解决; 尽pipe在某些情况下您可能必须使用接口(Java)或协议(Obj-C)。 由于C ++不知道任何这样的事情,你将不得不使用抽象基类,这意味着你不能完全摆脱在C ++中的inheritance。

组合通常更符合逻辑,它提供了更好的抽象,更好的封装,更好的代码重用(特别是在非常大的项目中),并且不太可能在远处破坏任何东西,只是因为在代码中的任何地方做了单独的更改。 这也使得维护“ 单一责任原则 ”变得更加容易,这个原则经常被概括为“ 一个阶级改变不应该有一个以上的理由 ”,这意味着每一个阶级都是为了一个特定的目的而存在的只有与其目的直接相关的方法。 另外,如果inheritance树非常浅,那么即使项目开始变得非常庞大,也可以更轻松地保持概览。 许多人认为inheritance代表我们的现实世界相当好,但这不是事实。 现实世界比inheritance使用更多的构成。 几乎每个可以握在手中的真实世界对象都是由其他较小的真实世界对象组成的。

虽然有构成的缺点。 如果完全忽略inheritance,只关注构图,则会注意到,如果使用inheritance,则通常必须编写一些不必要的额外代码行。 你有时也被迫重复自己,这违反了DRY原则 (DRY =不要重复自己)。 另外组合通常需要委托,一个方法只是调用另一个对象的另一个方法,没有其他代码围绕这个调用。 这样的“双方法调用”(可能容易扩展到三重或四重方法调用,甚至比这更远)比inheritance性能要差得多,只要inheritance父级方法即可。 调用inheritance的方法可能与调用非inheritance的方法的速度一样快,也可能稍慢,但通常比两个连续的方法调用仍然快。

您可能已经注意到,大多数OO语言不允许多重inheritance。 虽然有几种情况下多重inheritance可以真正为你买东西,但是这些都是比例外的例外情况。 当你遇到一种情况时,你认为“多重inheritance将是解决这个问题的一个非常酷的function”,通常你应该重新考虑inheritance,因为即使它可能需要一些额外的代码行,基于构图的解决scheme往往会变得更加优雅,灵活和前瞻性。

inheritance是一个很酷的function,但是恐怕过去几年它已经被滥用了。 人们把遗产看作是一把可以钉死的锤子,无论它是钉子,螺丝钉,还是完全不同的东西。

在这里没有find满意的答案,于是我写了一个新的。

为了理解为什么“ 更喜欢构成而不是inheritance”,我们首先需要找回这个缩略语中省略的假设。

inheritance有两个好处: 子types和子types

  1. types意味着符合types(接口)签名,即一组API,并且可以覆盖部分签名以实现子types多态性。

  2. 子类化意味着方法实现的隐式重用。

这两个好处带来了两个不同的inheritance目的:面向子types和面向代码重用。

如果代码重用是唯一的目的,那么子类化可能会比他需要的多一些,也就是说父类的一些公共方法对于子类没有多大意义。 在这种情况下,而不是有利于构成而不是inheritance,组合是需要的 。 这也是“is-a”与“has-a”概念的来源。

所以只有当子types被使用时,也就是后来以多态的方式使用新类时,我们是否面临selectinheritance或组合的问题。 这是在讨论的缩略语中被省略的假设。

为了使子types符合types签名,这意味着组合总是要暴露types的API的数量。 现在,这个折衷点开始了:

  1. inheritance提供直接的代码重用,如果不重写,而组合必须重新编码每个API,即使它只是一个简单的委托工作。

  2. inheritance提供了直接的开放recursion通过内部多态网站,即调用重写方法(或甚至types )在另一个成员函数,公共或私人(虽然不鼓励 )。 打开recursion可以通过组合来模拟 ,但是它需要额外的努力,并不总是可行的(?)。 这个重复问题的答案谈到类似的东西。

  3. inheritance暴露受保护的成员。 这打破了父类的封装,并且如果被子类使用,则引入子类与其父类之间的另一个依赖关系。

  4. 构件具有控制反转的装饰 ,它的依赖可以dynamic注入,如装饰器模式和代理模式所示 。

  5. 组合具有面向组合器编程的优点,即以类似于组合模式的方式工作。

  6. 在编程之后立即编写界面 。

  7. 构图具有简单多重inheritance的优点。

考虑到上述折衷,我们因此宁愿组合而不是inheritance。 然而对于紧密相关的类,也就是说,当隐式代码重用确实有利时,或者期望开放recursion的魔力时,inheritance应该是select。

我的一般经验法则: 在使用inheritance之前,考虑组合是否更有意义。

原因: 子类化通常意味着更多的复杂性和连通性,即难以改变,维护和扩展而不会犯错误。

Sun的Tim Boudreau提供了一个更加完整和具体的答案 :

我所看到的使用inheritance的常见问题是:

  • 无辜的行为可能会有意想不到的结果 – 这是一个典型的例子,在子类实例字段被初始化之前,调用来自超类构造函数的可重写方法。 在一个完美的世界里,没有人会这样做。 这不是一个完美的世界。
  • 它提供了不正当的诱惑,使得子类人员能够对方法调用的顺序做出假设 – 如果超类随着时间的推移,这种假设往往不稳定。 另见我的烤面包机和咖啡壶比喻 。
  • 类越来越重 – 你不一定知道你的超类在构造函数中做了什么,或者它将使用多less内存。 所以构build一些天真的轻量级对象可能比你想象的要昂贵得多,而且如果超类发展
  • 它鼓励子类的爆炸 。 课堂上课费用时间,更多课程花费内存。 这可能是一个非问题,直到您处理NetBeans规模的应用程序,但在那里,我们遇到了实际问题,例如菜单速度较慢,因为菜单的第一个显示会触发大量的类加载。 我们通过转向更多的声明性语法和其他技术来解决这个问题,但是这也需要花费时间来解决。
  • 这会让事情变得更加困难 – 如果你公开创build了一个类,那么交换超类将会破坏子类 – 这是一个select,一旦你公开代码,你就结婚了。 所以,如果你没有改变你的超类的真正function,那么如果你使用的话,你会有更多的自由来改变事情,而不是扩展你需要的东西。 举个例子,JPanel子类 – 这通常是错误的; 如果这个子类在某个地方是公开的,那么你就再也没有机会去重新审视这个决定了。 如果以JComponent getThePanel()方式访问它,您仍然可以这样做(提示:将组件的模型作为您的API进行公开)。
  • 对象层次结构不能缩放(或者比以后进行缩放要困难得多) – 这是经典的“太多层”问题。 我将在下面讨论这个问题,以及AskTheOracle模式如何解决它(尽pipe它可能会冒犯OOP纯粹主义者)。

我想要做什么,如果你允许inheritance,你可以用一粒盐吃:

  • 除了常量外,不会公开任何字段
  • 方法应是抽象的或最终的
  • 不要调用超类构造函数的方法

所有这些对小项目的适用比对大项目的适用性小一些,对私人课程的适用比对公共项目小

inheritance是非常强大的,但是你不能强迫它(参见: 圆椭圆问题 )。 如果你真的不能完全确定一个真正的“是”一个亚型关系,那么最好还是写作。

inheritance在子类和超类之间build立了强有力的关系; 子类必须了解超类的实现细节。 创build超级类是非常困难的,当你必须考虑如何扩展。 您必须仔细logging类不variables,并指出可重复方法在内部使用的其他方法。

如果层次结构真正代表了一种关系,那么inheritance有时是有用的。 它涉及到开放 – 封闭的原则,其中指出,类应该closures修改,但可以延长。 这样你可以有多态性; 有一个处理超types和它的方法的通用方法,但是通过dynamic调度来调用子类的方法。 这是灵活的,并且有助于创build间接性,这在软件中是必不可less的(对于实现细节知之甚less)。

但是,inheritance很容易被滥用,并且会产生额外的复杂性,类之间的依赖关系很难实现。 理解程序执行过程中发生的事情,由于层次和方法调用的dynamicselect而变得相当困难。

我会build议使用作为默认的作曲。 它更加模块化,并提供了后期绑定的好处(您可以dynamic更改组件)。 另外,更容易分开testing。 如果你需要使用一个class级的方法,你不是被迫成为某种forms(Liskov替代原则)。

你需要看看鲍伯叔叔SOLID原则的Liskov替代原则 。 🙂

假设一架飞机只有两个部分:发动机和机翼。
然后有两种方法来devise一个飞机class。

 Class Aircraft extends Engine{ var wings; } 

现在你的飞机可以开始固定翅膀
并在飞行中将它们更改为旋转翼。 基本上是这样
一个带翅膀的引擎。 但是如果我想改变呢
发动机在飞行?

基类Engine公开了一个mutator来改变它
属性,或者我重新deviseAircraft为:

 Class Aircraft { var wings; var engine; } 

现在,我可以随时更换我的引擎。

“优先于inheritance构成”是一个devise原则,它说不要滥用inheritance,当它不适合。

如果两个实体之间不存在真实世界的层次关系,则不要使用inheritance,而要使用合成。 构图代表“有”关系。

例如汽车有一个车轮,车身,发动机等,但如果你在这里inheritance,它会变成车轮 – 这是不正确的。

有关进一步的解释,请参阅比inheritance更喜欢构图

当你想“复制”/公开基类的API,你使用inheritance。 当您只想“复制”function时,请使用委派。

其中一个例子:你想从列表中创build一个堆栈。 堆栈只有pop,push和peek。 你不应该使用inheritance,因为你不想在栈中使用push_back,push_front,removeAt等types的function。

这两种方式可以一起生活,相互支持。

Composition只是玩它的模块化:你创build类似于父类的接口,创build新的对象并委托对它的调用。 如果这些物体不需要知道对方的话,那么使用构图就相当安全和容易。 这里有这么多的可能性。

但是,如果父类出于某种原因需要访问由“缺乏经验的程序员”的“子类”提供的函数,那么它可能看起来是使用inheritance的好地方。 父类可以调用它自己的抽象“foo()”,它被子类覆盖,然后它可以给抽象基础赋值。

它看起来像个不错的主意,但在很多情况下,最好给这个类一个实现foo()的对象(甚至手工设置提供的foo()的值),而不是从一些基类inheritance新的类函数foo()被指定。

为什么?

因为inheritance是移动信息的一个不好的方法

这个组合在这里有一个真正的优势:关系可以颠倒过来:“父类”或“抽象工作者”可以聚合实现特定接口的任何特定“子”对象+ 任何子类可以在任何其他types的父类中设置,这是types 。 可以有任意数量的对象,例如MergeSort或QuickSort可以对实现抽象比较接口的任何对象列表进行sorting。 或者换句话说,任何实现“foo()”的对象组和可以使用具有“foo()”对象的其他对象组可以一起玩。

我可以想到使用inheritance的三个真正的原因:

  1. 你有很多具有相同接口的类,你想节省时间写它们
  2. 您必须为每个对象使用相同的基类
  3. 你需要修改私有variables,在任何情况下都不能公开

如果这是真的,那么可能有必要使用inheritance。

理由1没有什么不好,在你的对象上有一个坚实的接口是非常好的事情。 这可以使用组合或inheritance,没有问题 – 如果这个接口是简单的,不会改变。 通常inheritance在这里是非常有效的。

如果原因是数字2,它会有点棘手。 你真的只需要使用相同的基类? 一般来说,只使用相同的基类是不够的,但它可能是你的框架的要求,这是一个无法避免的devise考虑。

但是,如果你想使用私有variables,那么情况3,那么你可能会遇到麻烦。 如果你认为全局variables是不安全的,那么你应该考虑使用inheritance访问私有variables也是不安全的 。 请注意,全局variables并不是那么糟糕 – 数据库本质上是一组全局variables。 但是,如果你能处理它,那就很好了。

所有现有的答案都很好地解释了为什么组合往往比inheritance更可取。 但是,确实有inheritance比较适合的情况,因此有一个很好的“testing”来知道我们是否处于这种情况是很重要的。

Circle-Ellipse问题很好地说明了为什么“is-a”实际上不是检测何时使用inheritance的好方法。 事实上, 即使一个圆是一个椭圆 ,让Circle类inheritanceEllipse类也是一个坏主意,因为有些事情可以用椭圆形,但是圆形不能。 例如,椭圆可以伸展,但圆形不能。 所以你可以有ellipse.stretch() ,但不是circle.stretch()

我认为一个更好的testing是“是 – 一个”“具有多function性” 。 换句话说,只要子类可以多态使用,最好使用inheritance。 “是”的关系是多态使用的必要条件,但这是不够的。 超类提供的每个function也可以由子类提供也是非常重要的。 所以当你有一个“是某种”另一个类的类,但是增加了一些约束时,你就不应该使用inheritance,因为它不能被多态使用。

换句话说, inheritance不是共享属性,而是共享function 。 Typically, "is-a" works as a test whether all getters of the superclass make sense in the subclass, while "has-as-much-functionality-as" works as a test whether all setters of the superclass make sense in the subclass. Together, the getters and setters define the "functionality" of a class. The getters alone define the "properties" of a class. By "setter", I mean any function that mutates the state of the object., not just the trivial ones.

Other answers/comments pretty much said the same things, but I feel mine adds some clarity.

Aside from is a/has a considerations, one must also consider the "depth" of inheritance your object has to go through. Anything beyond five or six levels of inheritance deep might cause unexpected casting and boxing/unboxing problems, and in those cases it might be wise to compose your object instead.

A simple way to make sense of this would be that inheritance should be used when you need an object of your class to have the same interface as its parent class, so that it can thereby be treated as an object of the parent class (upcasting). Moreover, function calls on a derived class object would remain the same everywhere in code, but the specific method to call would be determined at runtime (ie the low-level implementation differs, the high-level interface remains the same).

Composition should be used when you do not need the new class to have the same interface, ie you wish to conceal certain aspects of the class' implementation which the user of that class need not know about. So composition is more in the way of supporting encapsulation (ie concealing the implementation) while inheritance is meant to support abstraction (ie providing a simplified representation of something, in this case the same interface for a range of types with different internals).

Subtyping is appropriate and more powerful where the invariants can be enumerated , else use function composition for extensibility.

I agree with @Pavel, when he says, there are places for composition and there are places for inheritance.

I think inheritance should be used if your answer is an affirmative to any of these questions.

  • Is your class part of a structure that benefits from polymorphism ? For example, if you had a Shape class, which declares a method called draw(), then we clearly need Circle and Square classes to be subclasses of Shape, so that their client classes would depend on Shape and not on specific subclasses.
  • Does your class need to re-use any high level interactions defined in another class ? The template method design pattern would be impossible to implement without inheritance. I believe all extensible frameworks use this pattern.

However, if your intention is purely that of code re-use, then composition most likely is a better design choice.

The answer is quite simple

When you have an is-a relation between two classes (example dog is a canine) you go for inheritance.

On the other hand when you have has-a or some adjective relationship between two classes (student has courses) or (teacher studies courses) you chose composition.

A rule of thumb I have heard is inheritance should be used when its a "is-a" relationship and composition when its a "has-a". Even with that I feel that you should always lean towards composition because it eliminates a lot of complexity.

Inheritance is a very powerfull machanism for code reuse. But needs to be used properly. I would say that inheritance is used correctly if the subclass is also a subtype of the parent class. As mentioned above, the Liskov Substitution Principle is the key point here.

Subclass is not the same as subtype. You might create subclasses that are not subtypes (and this is when you should use composition). To understand what a subtype is, lets start giving an explanation of what a type is.

When we say that the number 5 is of type integer, we are stating that 5 belongs to a set of possible values (as an example, see the possible values for the Java primitive types). We are also stating that there is a valid set of methods I can perform on the value like addition and subtraction. And finally we are stating that there are a set of properties that are always satisfied, for example, if I add the values 3 and 5, I will get 8 as a result.

To give another example, think about the abstract data types, Set of integers and List of integers, the values they can hold are restricted to integers. They both support a set of methods, like add(newValue) and size(). And they both have different properties (class invariant), Sets does not allow duplicates while List does allow duplicates (of course there are other properties that they both satisfy).

Subtype is also a type, which has a relation to another type, called parent type (or supertype). The subtype must satisfy the features (values, methods and properties) of the parent type. The relation means that in any context where the supertype is expected, it can be substitutable by a subtype, without affecting the behaviour of the execution. Let's go to see some code to exemplify what I'm saying. Suppose I write a List of integers (in some sort of pseudo language):

 class List { data = new Array(); Integer size() { return data.length; } add(Integer anInteger) { data[data.length] = anInteger; } } 

Then, I write the Set of integers as a subclass of the List of integers:

 class Set, inheriting from: List { add(Integer anInteger) { if (data.notContains(anInteger)) { super.add(anInteger); } } } 

Our Set of integers class is a subclass of List of Integers, but is not a subtype, due to it is not satisfying all the features of the List class. The values, and the signature of the methods are satisfied but the properties are not. The behaviour of the add(Integer) method has been clearly changed, not preserving the properties of the parent type. Think from the point of view of the client of your classes. They might receive a Set of integers where a List of integers is expected. The client might want to add a value and get that value added to the List even if that value already exist in the List. But her wont get that behaviour if the value exists. A big suprise for her!

This is a classic example of an improper use of inheritance. Use composition in this case.

(a fragment from: use inheritance properly ).

Composition v/s Inheritance is a wide subject. There is no real answer for what is better as I think it all depends on the design of the system.

Generally type of relationship between object provide better information to choose one of them.

If relation type is "IS-A" relation then Inheritance is better approach. otherwise relation type is "HAS-A" relation then composition will better approach.

Its totally depend on entity relationship.

As many people told, I will first start with the check – whether there exists an "is-a" relationship. If it exists I usually check the following:

Whether the base class can be instantiated. That is, whether the base class can be non-abstract. If it can be non-abstract I usually prefer composition

Eg 1. Accountant is an Employee. But I will not use inheritance because a Employee object can be instantiated.

Eg 2. Book is a SellingItem. A SellingItem cannot be instantiated – it is abstract concept. Hence I will use inheritacne. The SellingItem is an abstract base class (or interface in C#)

你对这种方法有什么看法?

Also, I support @anon answer in Why use inheritance at all?

The main reason for using inheritance is not as a form of composition – it is so you can get polymorphic behaviour. If you don't need polymorphism, you probably should not be using inheritance.

@MatthieuM. says in https://softwareengineering.stackexchange.com/questions/12439/code-smell-inheritance-abuse/12448#comment303759_12448

The issue with inheritance is that it can be used for two orthogonal purposes:

interface (for polymorphism)

implementation (for code reuse)

REFERENCE

  1. Which class design is better?
  2. Inheritance vs. Aggregation

What do you want to force yourself (or another programmer) to adhere to and when do you want to allow yourself (or another programmer) more freedom. It has been argued that inheritance is helpful when you want to force someone into a way of dealing with/solving a particular problem so they can't head off in the wrong direction.

Is-a and Has-a is a helpful rule of thumb.

A real world example of when Composition is better than Inheritance.

Assume you have a BaseClass where T is injected by a concrete class.

 public BaseClass<T>{} 

At first glance this looks nice because you can inject any type you want and use this type to change property behavior within the class; whereby T is referenced like this:

 public T SomeProperty {get;set;} 

A possible concrete class using inheritance looks like this:

 public class SubClass : BaseClass<string> 

But what happens if you need to have that base property handle different types? Do you create one class per type? No just use containment instead. 喜欢这个:

 public class SubClass{ private BaseClass<List<string>> BaseForList = new BaseClass<List<string>>(); private BaseClass<List<ofSomeType>> BaseForListOfSometype = new BaseClass<List<ofSomeType>(); } 

You can see from the example above that the SubClass is open to expand in any way needed. It can in essence be more than one implementation of a single baseclass. It's easily morphed into just that type giving you very specific access to property types. This is better than inheriting and creating multiple class derived from the BaseClass with one caveat…

Addressibility to "Contained" things takes on a different signature which is simply preceding the thing wanted (SomeProperty) with the instance of the class. 喜欢这个:

 BaseForList.SomeProperty = something; BaseForListOfSomeType.SomeProperty = somethingelse; 

Because of this, it's best to create short names for contained things…so your code can look like this (Just make sure that the short names have good meaning)…

 BA.SomeProperty = something; BL.SomeProperty = somethingelse;