《Effective java》读书记录-第16条-复合优先于继承
来源:互联网 发布:淘宝神笔有什么用 编辑:程序博客网 时间:2024/04/30 10:49
继承(当一个类扩展另一个类的时候)是实现代码重用的有力手段,但它不是最好的方式。
与方法调用不同的是,继承打破了封装性(子类依赖与超类中特定功能的实现细节)。
下面的例子为了统计Set的操作次数,通过继承的方式实现的。
public class InstrumentHashSet<E> extends HashSet<E> { private int addCount=0; public InstrumentHashSet () { } public InstrumentHashSet (int initCap,int loadFactor) { super(initCap,loadFactor); } @Override public boolean add(E e) { System.out.println("add"); addCount++; return super.add(e); } @Override public boolean addAll(Collection<? extends E> c) { System.out.println("addAll"); addCount+=c.size(); return super.addAll(c); } public int getAddCount(){ return addCount; }}
public void testFirst(){ InstrumentHashSet<String> set=new InstrumentHashSet<String>(); set.addAll(Arrays.asList("a","b","c")); System.out.println(set.getAddCount()); }
在测试代码中,通过addAll方式添加数据到Set中。
这段代码看起来没有任何问题,预期的结果是输出3,然而实际结果却是6。
导致这一错误的原因是,HashSet.addAll()方法是遍历传入的集合,然后调用HashSet.add()添加到Set中去。
现在我们发现了错误的原因,那把统计的那条语句注释掉,就可以解决错误了。
@Override public boolean addAll(Collection<? extends E> c) { System.out.println("addAll"); //addCount+=c.size(); return super.addAll(c); }这个方法虽然目前的Java版本是可用的,如果之后的版本修改这个方法的话,那么程序又会出现新的问题,这就埋下一个隐患了。
那么要怎么来处理这个问题。
新建一个类ForwardingSet,在ForwardingSet中添加一个final的Set私有域,这种设计称为“复合”。
ForwardingSet实现Set的接口,并通过包含的Set的实例去返回这些接口方法,这种设计被称为“转发”。
这样得到的类将会非常稳固,它不依赖于Set类的实现细节。即使Set类添加了新的方法,也不会影响ForwardingSet。
public class InstrumentHashSet<E> extends ForwardingSet<E> { private int addCount=0; public InstrumentHashSet (Set<E> s) { super(s); } @Override public boolean add(E e) { System.out.println("add"); addCount++; return super.add(e); } @Override public boolean addAll(Collection<? extends E> c) { System.out.println("addAll"); addCount+=c.size(); return super.addAll(c); } public int getAddCount(){ return addCount; }}
public class ForwardingSet<E> implements Set<E> { private final Set<E> set; public ForwardingSet (Set<E> set) { this.set=set; } public int size() { return this.set.size(); } public boolean isEmpty() { return this.set.isEmpty(); } public boolean contains(Object o) { return this.set.contains(o); } public Iterator<E> iterator() { return this.set.iterator(); } public void clear() { this.set.clear(); }}
包装类几乎没什么缺点,但不适用于回调框架(callback framework)
只有当子类真正是超类的子类型(subtype)时(A和B两个类确实存在“is-a”关系),才适合用继承。
继承机制会把超类API中的所有缺陷传播到子类中,而复合则允许设计新的API来隐藏这些缺陷。所以在决定使用继承前一定要考虑,试图扩展的类是否有缺陷,是否愿意把那些缺陷传播到类的API中。
继承的功能非常强大,但是也存在许多的问题,因为它违背了封装原则。
0 0
- 《Effective java》读书记录-第16条-复合优先于继承
- Effective Java 第16条 : 复合优先于继承
- Effective Java学习--第16条:复合优先于继承
- 第16条:复合优先于继承
- 第16条:复合优先于继承
- 第16条:复合优先于继承
- 《Effective java》读书记录-第25条-列表优先于数组
- Effective Java读书笔记-复合优先于继承
- effective java(16) 之复合优先于继承
- Effective Java学习笔记:复合优先于继承
- 《Effective java》读书记录-第19条-接口只用于定义类型
- 《Effective java》读书记录-第22条-优先考虑静态成员类
- 《Effective java》读书记录-第26条-优先考虑泛型
- Effective Java 16:复合优先于继承 Favor composition over inheritance
- 第十六条:复合优先于继承
- 《Effective java》读书记录-第17条-要么为继承而设计,并提供文档说明,要么就禁止继承
- 《Effective java》读书记录-第15条-使可变性最小化
- 《Effective java》读书记录-第18条-接口优于抽象
- Android的bitmap遇到内存溢出
- maven问题处理
- libevent5
- MySQL修改root密码的多种方法
- 如何使用hbase自带的zookeeper
- 《Effective java》读书记录-第16条-复合优先于继承
- 配置成服务器
- Java正则表达式的基本用法
- 缓存算法
- ArcGIS Server for Java
- 【Java基础】动态代理实现AOP之控制事务
- androidEventBus 与 greenrobot的EventBus
- 数据库优化
- 记一个用RxJava遇到的问题