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

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

组 合 关 系

继 承 关 系

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

最近在写得一分新代码:

     public interface IEntity{}

     public interface IEntityContainer
{
string Name { get;}
int EntityId { get;}
IList<IEntity> EntityContainer{ get;}
} public class XEntityContainer : IEntityContainer
{
public XEntityContainer()
{
//Name = ...;
//EntityId = ...;
//EntityContainer = ...;
} public string Name{get; private set;}
public int EntityId{get; private set;}
public IList<IEntity> EntityContainer{ get; private set;}
} public class YEntityContainer : IEntityContainer
{
public YEntityContainer()
{
//Name = ...;
//EntityId = ...;
//EntityContainer = ...;
} public string Name { get;private set;}
public int EntityId { get;private set;}
public IList<IEntity> EntityContainer{ get; private set;}
}

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

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

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

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

     public interface IEntity{}

     public interface IEntityContainer
{
string Name { get;}
int EntityId { get;}
IList<IEntity> EntityContainer{ get;}
} public class EntityContainerBase : IEntityContainer
{
public string Name{get; protected set;}
public int EntityId{get; protected set;}
public IList<IEntity> EntityContainer{ get; protected set;}
} public class XEntityContainer : EntityContainerBase
{
public XEntityContainer()
{
//Name = ...;
//EntityId = ...;
//EntityContainer = ...;
}
} public class YEntityContainer : EntityContainerBase
{
public YEntityContainer()
{
//Name = ...;
//EntityId = ...;
//EntityContainer = ...;
}
}

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

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

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

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

     public interface IEntity{}

     public struct Container
{
public string Name{get;set;};
public int EntityId{get;set;};
public IList<IEntity> EntityList{get;set;};
} public interface IEntityContainer
{
string Name { get;}
int EntityId { get;}
IList<IEntity> EntityContainer{ get;}
} public class XEntityContainer : IEntityContainer
{
public XEntityContainer()
{
//m_Container.Name = ...;
//m_Container.EntityId = ...;
//m_Container.EntityList = ...;
} public string Name { get{return m_Container.Name;}}
public int EntityId { get{return m_Container.EntityId;};}
public IList<IEntity> EntityContainer{ get{return m_Container.EntityList;};} private Container m_Container;
} public class YEntityContainer : IEntityContainer
{
public YEntityContainer()
{
//m_Container.Name = ...;
//m_Container.EntityId = ...;
//m_Container.EntityList = ...;
} public string Name { get{return m_Container.Name;}}
public int EntityId { get{return m_Container.EntityId;};}
public IList<IEntity> EntityContainer{ get{return m_Container.EntityList;};} private Container m_Container;
}

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

最新文章

  1. [转]ASP.NET Core 中间件详解及项目实战
  2. noj[1581] 筷子
  3. ELK_日志分析系统Logstash+ElasticSearch+Kibana4
  4. UVa Problem 10132 File Fragmentation (文件还原) 排列组合+暴力
  5. SQL注入攻击及防范
  6. 用变量a给出下面的定义
  7. 黑马程序员_Java面向对象1_封装
  8. 剑指offier第4题
  9. evak购物车--团队博客
  10. gridContro使用随记
  11. 优易软件-关于click事件在苹果手机失效的问题
  12. sea.js 个人入门
  13. Mike and strings CodeForces - 798B (又水又坑)
  14. Go 语言 HTTP Server 源码分析
  15. Python基础(十) __init__与__new__区别
  16. oracle数据恢复方法
  17. 从实践出发:微服务布道师告诉你Spring Cloud与Spring Boot他如何选择
  18. [dig]使用dig查看当前网络连通情况
  19. Shuffle机制
  20. hadoop之定制自己的Partitioner

热门文章

  1. HTML5视频Video 音频Audio
  2. Bash漏洞批量检测工具与修复方案
  3. Advanced SystemCare 系统优化软件
  4. certbot+nginx (仅用作个人纪录)
  5. IIC
  6. HDU 5936 Difference
  7. 解释器模式(Interpreter Pattern)
  8. php7 编译安装 apache
  9. MyBatis代码自动生成(利用命令)
  10. GitLab常见使用方法