组合or继承
面向对象设计有一个原则“优先使用对象组合,而不是继承”。
下面是两者优缺点的比较:
|
组 合 关 系 |
继 承 关 系 |
|
优点:不破坏封装,整体类与局部类之间松耦合,彼此相对独立 |
缺点:破坏封装,子类与父类之间紧密耦合,子类依赖于父类的实现,子类缺乏独立性 |
|
优点:具有较好的可扩展性 |
缺点:支持扩展,但是往往以增加系统结构的复杂度为代价 |
|
优点:支持动态组合。在运行时,整体对象可以选择不同类型的局部对象 |
缺点:不支持动态继承。在运行时,子类无法选择不同的父类 |
|
优点:整体类可以对局部类进行包装,封装局部类的接口,提供新的接口 |
缺点:子类不能改变父类的接口 |
|
缺点:整体类不能自动获得和局部类同样的接口 |
优点:子类能自动继承父类的接口 |
|
缺点:创建整体类的对象时,需要创建所有局部类的对象 |
优点:创建子类的对象时,无须创建父类的对象 |
我们可以发现继承的缺点远远多于优点,尽管继承在学习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里塞。
组合or继承的更多相关文章
- 28-React state提升、组件组合或继承
Lifting State Up state提升 对于在React应用程序中更改的任何数据,应该有一个单一的数据源.通常,都是将state添加到需要渲染的组件.如果其他组件也需要它,您可以将其提升到最 ...
- Java(Android)编程思想笔记02:组合与继承、final、策略设计模式与适配器模式、内部类、序列化控制(注意事项)
1.组合和继承之间的选择 组合和继承都允许在新的类中放置子对象,组合是显式的这样做,而继承则是隐式的做. 组合技术通常用于想在新类中使用现有类的功能而非它的接口这种情形.即在新类中嵌入某个对象,让其实 ...
- oc随笔二:组合、继承
在oc中如果没有使用ARC的话,手动管理内存一定要注意处理好“野指针”,通常我们在释放指针的指向的地址时,都要将指针赋值为nil,这样能有效的防止野指针.常用的关键字:retain.assign .s ...
- (笔记):组合and继承之访问限制(一)
下面在介绍组合与继承之前,先介绍一下访问限制,访问限制:public.protected.private三者是按照授权的大小排序的.这里有个博客,对这三者有了经典的诠释.http://blog.csd ...
- Effective Java 第三版——18. 组合优于继承
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- 面向对象之组合VS继承:继承过时了?
在阅读Effective Java中的第16条时发现了一个有趣的机制或者说是模式,那就是组合(文中翻译为复用,但是作者认为组合更能体现这种模式的精神),并且文中建议使用组合. 那什么是组合, ...
- day 24 二十四、组合、继承、方法重写和重用、super()
一.组合 1.定义:自定义类的对象作为类的属性 A类的对象具备某一个属性,该属性的值是B类的对象 基于这种方式就把A类与B类组合到一起 对象既能使用A类中的数据与功能,也能使用B类中的数据与功能 2. ...
- 用组合取代继承能为 Activity 带来什么
用组合取代继承能为 Activity 带来什么 原文链接 : Composition over Inheritance,What it means for your Activities 原文作者 : ...
- 重新精读《Java 编程思想》系列之组合与继承
Java 复用代码的两种方式组合与继承. 组合 组合只需将对象引用置于新类中即可. 比如我们有一个B类,它具有一个say方法,我们在A类中使用B类的方法,就是组合. public class B { ...
- day25-静态、组合、继承
#!/usr/bin/env python # -*- coding:utf-8 -*- # ----------------------------------------------------- ...
随机推荐
- 移动web开发和移动app开发的区分
1.移动web开发 这部分跟web前端开发差别不大,使用的技术都是html+css+js.区别为手机浏览器是webkit的天下,pc端是IE的天 下.手机网页可以理解成pc网页的缩小版加一些触摸特性. ...
- wordpress(三)wordpress手动更新
第一:备份数据库还有文件 第二:从WP中文官网下载最新版WordPress,下载完毕解压到你电脑上. 第三:删除博客主机上的wp-includes和wp-admin目录. 第四:将解压在本地电脑的wo ...
- select,poll,epoll区别
select:忙轮询,一直在轮询,效率跟链接数成反比,资源限制 poll:轮询,不用一直轮询,有事件触发时轮询,资源限制 epoll:有事件触发时直接通知复杂度O(1)
- final评价Ⅱ
1.飞天小女警: 礼物挑选这个项目相比之前的发布功能更完善了些,但是整体界面还是不太美观,用户界面上呈现出的选项字不够清晰,使用起来不是很方便,但是增加了猜你喜欢的功能,可以根据用户的浏览记录猜测用户 ...
- 51nod 1228 序列求和 ( 1^k+2^k+3^k+...+n^k )
C为组合数,B为伯努利数 具体推到过程略 参考博客:http://blog.csdn.net/acdreamers/article/details/38929067# (我的式子和博客中的不一样,不过 ...
- LEETCODE —— Surrounded Regions
Total Accepted: 43584 Total Submissions: 284350 Difficulty: Medium Given a 2D board containing 'X' a ...
- javascript中bind函数的作用
javascript的bind的作用 <!DOCTYPE html> <html> <head> <meta charset="utf-8" ...
- java 中文转化为拼音
依赖架包:pinyin4j.jar package net.jeeshop.core.util; import net.sourceforge.pinyin4j.PinyinHelper; impor ...
- This is a TEST
I LOVE LINUX && PHP VERY MUCH AND MORE, ALL OPEN SOURCE PROJECT
- Centos6.5 设置Tomcat8 service服务实现自启动和服务管理
Centos6.5 设置Tomcat8 service服务实现自启动和服务管理 将tomcat设置成像apache,nginx一样. 用serviec xxxx start/stop/restart ...