组合or继承

摘要:
面向对象设计具有“优先考虑对象组合而不是继承”的原则。以下是两者优缺点的比较:组合关系继承关系的优点:不破坏封装,整体类和局部类之间的松散耦合,彼此相对独立;缺点:封装被破坏,子类和父类之间紧密耦合,子类依赖于父类的实现,子类缺乏独立性;优点:可扩展性好;缺点:支持扩展,然而,它通常具有以增加系统结构复杂性为代价支持动态组合的优点。

面向对象设计有一个原则“优先使用对象组合,而不是继承”。

下面是两者优缺点的比较:

组 合 关 系

继 承 关 系

优点:不破坏封装,整体类与局部类之间松耦合,彼此相对独立

缺点:破坏封装,子类与父类之间紧密耦合,子类依赖于父类的实现,子类缺乏独立性

优点:具有较好的可扩展性

缺点:支持扩展,但是往往以增加系统结构的复杂度为代价

优点:支持动态组合。在运行时,整体对象可以选择不同类型的局部对象

缺点:不支持动态继承。在运行时,子类无法选择不同的父类

优点:整体类可以对局部类进行包装,封装局部类的接口,提供新的接口

缺点:子类不能改变父类的接口

缺点:整体类不能自动获得和局部类同样的接口

优点:子类能自动继承父类的接口

缺点:创建整体类的对象时,需要创建所有局部类的对象

优点:创建子类的对象时,无须创建父类的对象

  

我们可以发现继承的缺点远远多于优点,尽管继承在学习OOP的过程中得到了大量的强调,但并不意味着应该尽可能地到处使用它。

相反,使用它时要特别慎重。

只有在清楚知道继承在所有方法中最有效的前提下,才可考虑它。

 继承最大的优点就是扩展简单,但大多数缺点都很致命,但是因为这个扩展简单的优点太明显了,很多人并不深入思考,所以造成了太多问题。

虽然笔者的日常工作已经遭遇了太多的Legacy Code因为继承而导致的问题,但是在写新代码时,仍然容易陷入继承而无法自拔。

最近在写得一分新代码:

复制代码
 1     public interface IEntity{}
 5     
 6     public interface IEntityContainer
 7     {
 8         string Name { get;}
 9         int EntityId { get;}
10         IList<IEntity> EntityContainer{ get;}
11     }
12     
13     public class XEntityContainer : IEntityContainer
14     {
15         public XEntityContainer()
16         {
17             //Name = ...;
18             //EntityId = ...;
19             //EntityContainer = ...;
20         }
21         
22         public string Name{get; private set;}
23         public int EntityId{get; private set;}
24         public IList<IEntity> EntityContainer{ get; private set;}
25     }
26     
27     public class YEntityContainer : IEntityContainer
28     {
29         public YEntityContainer()
30         {
31             //Name = ...;
32             //EntityId = ...;
33             //EntityContainer = ...;
34         }
35         
36         public string Name { get;private set;}
37         public int EntityId { get;private set;}
38         public IList<IEntity> EntityContainer{ get; private set;}
39     }
复制代码

Code Review时觉得如果所有的子类都会包含这三行的话,其实是有些duplication的:

1 public string Name { get;private set;}
2 public int EntityId { get;private set;}
3 public IList<IEntity> EntityContainer{ get; private set;}

所以就建议使用组合的方式引入一个新的类型来提供这几项信息。

但,跟着直觉就把Code写成了这样子:

复制代码
 1     public interface IEntity{}
 5     
 6     public interface IEntityContainer
 7     {
 8         string Name { get;}
 9         int EntityId { get;}
10         IList<IEntity> EntityContainer{ get;}
11     }
12     
13     public class EntityContainerBase : IEntityContainer
14     {
15         public string Name{get; protected set;}
16         public int EntityId{get; protected set;}
17         public IList<IEntity> EntityContainer{ get; protected set;}
18     }
19     
20     public class XEntityContainer : EntityContainerBase
21     {
22         public XEntityContainer()
23         {
24             //Name = ...;
25             //EntityId = ...;
26             //EntityContainer = ...;
27         }
28     }
29     
30     public class YEntityContainer : EntityContainerBase
31     {
32         public YEntityContainer()
33         {
34             //Name = ...;
35             //EntityId = ...;
36             //EntityContainer = ...;
37         }
38     }
复制代码

就这样一个好好的二层继承,好好的interface继承,被掰成了三层结构。

比较“坏”的是这种潜意识里依然把继承依然当成了第一选择。

根据同一项目里已有的一段新Code,可以知道将来有些utility方法肯定会不断地往EntityContainerBase里加,直到有一天把它变成Legacy...

我更加倾向于我们应该这样改:

复制代码
 1     public interface IEntity{}
 5     
 6     public struct Container
 7     {
 8         public string Name{get;set;};
 9         public int EntityId{get;set;};
10         public IList<IEntity> EntityList{get;set;};
11     }
12     
13     public interface IEntityContainer
14     {
15         string Name { get;}
16         int EntityId { get;}
17         IList<IEntity> EntityContainer{ get;}
18     }
19     
20     public class XEntityContainer : IEntityContainer
21     {
22         public XEntityContainer()
23         {
24             //m_Container.Name = ...;
25             //m_Container.EntityId = ...;
26             //m_Container.EntityList = ...;
27         }
28         
29         public string Name { get{return m_Container.Name;}}
30         public int EntityId { get{return m_Container.EntityId;};}
31         public IList<IEntity> EntityContainer{ get{return m_Container.EntityList;};}
32         
33         private Container m_Container;
34     }
35     
36     public class YEntityContainer : IEntityContainer
37     {
38         public YEntityContainer()
39         {
40             //m_Container.Name = ...;
41             //m_Container.EntityId = ...;
42             //m_Container.EntityList = ...;
43         }
44         
45         public string Name { get{return m_Container.Name;}}
46         public int EntityId { get{return m_Container.EntityId;};}
47         public IList<IEntity> EntityContainer{ get{return m_Container.EntityList;};}
48         
49         private Container m_Container;
50     }
复制代码

多么漂亮的二层结构,没有任何Base类,将来的公共方法,Utility方法不会“无脑”的往Base里塞。

http://www.cnblogs.com/Cmpl/p/5463727.html#3424069

免责声明:文章转载自《组合or继承》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇jquery -- 触屏设备touch事件Linux错误代码含义下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Delphi源程序格式书写规范

Delphi源程序格式书写规范     1,规范简介   本规范主要规定Delphi源程序在书写过程中所应遵循的规则及注意事项。编写该规范的目的是使公司软件开发人员的源代码书写习惯保持一致。这样做可以使每一个组员都可以理解其它组员的代码,以便于源代码的二次开发记忆系统的维护。 2,一般格式规范 2.1 缩进   缩进就是在当源程序的级改变时为增加可读性而露...

[大数据技术]datax的安装以及使用

1、datax简述 DataX 是阿里巴巴集团内被广泛使用的离线数据同步工具/平台,实现包括 MySQL、Oracle、SqlServer、Postgre、HDFS、Hive、ADS、HBase、TableStore(OTS)、MaxCompute(ODPS)、DRDS 等各种异构数据源之间高效的数据同步功能。  datax的开源地址:https://g...

Java各种反射性能对比

对各种方法实现get方法的性能进行了一个测试。 总共有5个测试,,每个测试都是执行1亿次 1. 直接通过Java的get方法 2.通过高性能的ReflectAsm库进行测试 3.通过Java Class类自带的反射获得Method测试 4.使用Java自带的Property类获取Method测试 5.BeanUtils的getProperty测试 1 测试...

后台发送请求,HttpClient的post,get各种请求,带header的请求

HttpClient依赖jar包: <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.2</...

c# 免注册调用大漠插件100%完美识别文字

c#免注册调用大漠插件100%完美识别文字 下载:https://download.csdn.net/download/xxq931123/10875122 绑定 模式:http://zy.anjian.com/?action-viewthread-tid-239647 test 发QQ消息: public MainForm() {...

asp.netcore 读取配置文件

提到“配置”二字,我想绝大部分.NET开发人员脑海中会立即浮现出两个特殊文件的身影,那就是我们再熟悉不过的app.config和web.config,多年以来我们已经习惯了将结构化的配置定义在这两个XML格式的文件之中。到了.NET Core的时代,很多我们习以为常的东西都发生了改变,其中就包括定义配置的方式。总的来说,新的配置系统显得更加轻量级,并且具有...