组合or继承

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

下面是二者优缺点的比较:spa

组 合 关 系设计

继 承 关 系code

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

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

优势:具备较好的可扩展性继承

缺点:支持扩展,可是每每以增长系统结构的复杂度为代价接口

优势:支持动态组合。在运行时,总体对象能够选择不一样类型的局部对象ci

缺点:不支持动态继承。在运行时,子类没法选择不一样的父类get

优势:总体类能够对局部类进行包装,封装局部类的接口,提供新的接口

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

缺点:总体类不能自动得到和局部类一样的接口

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

缺点:建立总体类的对象时,须要建立全部局部类的对象

优势:建立子类的对象时,无须建立父类的对象

  

咱们能够发现继承的缺点远远多于优势,尽管继承在学习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里塞。

相关文章
相关标签/搜索