为什么复合优先于继承?

1.继承违反了封装原则,打破了封装性

2.继承会不必要的暴露API细节,称为隐患.比如通过直接访问底层使p.getProperty(K,V)的键值对可以不是String类型

3.继承限定了类的性能,它会把它的缺陷传递给子类

1.复合:不必扩展现有的Set类,而是在此类中加一个私有域,它引用现有类的一个实例
2.它的封装特性使得它更加健壮灵活
3.复合允许设计新的API隐藏父类的缺点

在继承中的例子

    public class InstrumentedHashSet<E> extends HashSet<E> {
//The number of attempted element insertions
//试图插入元素的数量
private int addCount = 0; public InstrumentedHashSet(){ } public InstrumentedHashSet(int initCap,float loadFactor){
super(initCap,loadFactor);
} @Override
public boolean add(E e){
addCount++;
return super.add(e);
} @Override
public boolean addAll(Collection<? extends E> c){
addCount+=c.size();
return super.addAll(c);
} public int getAddCount(){
return addCount;
} }

mian方法

InstrumentedHashSet<String> s = new InstrumentedHashSet<>();
s.addAll(Arrays.asList("Snap","Crackle","Pop")); //返回的值为6
//在hashSet内部 addAll方法是基于add实现的,
System.out.println(s.getAddCount());

使用复合改良这个例子

/**

* 新类

* 转发:新类中的每个实例方法都可以调用被包含的现有类实例中对应的方法并返回结果

 * @author JacXuan
*
* @param <E>
*/
public class ForwardingSet<E> implements Set<E> { private final Set<E> s; public ForwardingSet(Set<E> s) {
this.s = s;
}
....
/**

* 复合:不必扩展现有的Set类,而是在此类中加一个私有域,它引用现有类的一个实例

 * @author JacXuan
*
* @param <E>
*/
public class InstrumentedSet<E> extends ForwardingSet<E> { private int addCount =0; //引用ForwardingSet实例
public InstrumentedSet(Set<E> s) {
super(s);
} @Override
public boolean add(E e){
addCount++;
return super.add(e);
} @Override
public boolean addAll(Collection<? extends E> c){
addCount+=c.size();
return super.addAll(c);
}
public int getAddCount(){
return addCount;
} //将此类用于临时替换一个原本没有技术特性的Set实例
//不给出具体Dog类代码
// static void walk(Set<Dog> dogs){
// InstrumentedSet<Dog> iDogs = new InstrumentedSet<Dog>(capacity);
// }
}

//此包中的包装类可以被用来包装任何set实现,并且可以结合任何先前存在的构造器一起工作

        //Set<Date> s = new InstrumentedSet<Date>(new TreeSet<Date>(cmp));
//Set<E> s2 = new InstrumentedSet<E>(new HashSet<E>(capacity));

同样,继承也有使得功能复杂的类传播性更好,那么我们该何时使用继承呢

当子类真正是超类的子类型的时候,可以使用继承

EffectiveJava(16)复合优先于继承的更多相关文章

  1. EffectiveJava——复合优先于继承

    继承时实现代码重用的重要手段,但它并非永远是完成这项工作的最佳工具,不恰当的使用会导致程序变得很脆弱,当然,在同一个程序员的控制下,使用继承会变的非常安全.想到了很有名的一句话,你永远不知道你的用户是 ...

  2. Java复合优先于继承

    复合优于继承 继承打破了封装性(子类依赖父类中特定功能的实现细节) 合理的使用继承的情况: 在包内使用 父类专门为继承为设计,并且有很好的文档说明,存在is-a关系 只有当子类真正是父类的子类型时,才 ...

  3. 【Effective Java】6、使用复合优先于使用继承

    这个,不管是什么书都会这样说,因为常常我们并不需要继承,而只是想把类进行一定的扩展,而我们想扩展的属性或方法对应的类都有,这个时候如果两者是is a的关系,这种关系是确实存在的,那么就可以使用继承,不 ...

  4. Java - 复合模式优于继承

    继承是实现代码重用的方法之一,但使用不当则会导致诸多问题. 继承会破坏封装性,对一个具体类进行跨包访问级别的继承很危险. 即,子类依赖父类的实现细节. 如果父类的实现细节发生变化,子类则可能遭到破坏. ...

  5. effective-java学习笔记---优先使用泛型方法30

    泛型类型比需要在客户端代码中强制转换的类型更安全,更易于使用. 当你设计新的类型时,确保它们可以在没有这种强制转换的情况下使用. 这通常意味着使类型泛型化. 如果你有任何现有的类型,应该是泛型的但实际 ...

  6. Effecvtive Java Note

    代码应该被重用,而不是被拷贝 同大多数学科一样,学习编程的艺术首先要学会基本的规则,然后才能知道什么时候可以打破这些规则   创建和销毁对象 1.考虑用静态工厂方法代替构造器. 优势:有名称.不必再每 ...

  7. Effective Java-第4章

    第4章 类和接口 类和接口是Java程序设计语言的核心,它们也是Java语言的基本抽象单元.Java语言提供了许多强大的基本元素,供程序员用来设计类和接口. 13. 使类和成员的可访问性最小化 要区别 ...

  8. 读effection java

    1.考虑用静态工厂方法代替构造器 public static Boolean valueOf(boolean b){ return b?Boolean.TRUE:Boolean.FALSE; } 静态 ...

  9. Chapter 02:复合 VS 继承

    复合优先于继承,继承是实现代码重用的有力手段,并不是所有情况都适用,使用不当会导致软件变得很脆弱.与方法调用不同的是,继承打破了封装性. 总而言之,组合和继承,都能实现对类的扩展.但是要分具体情况用哪 ...

随机推荐

  1. linux后端跑redis

    http://blog.csdn.net/ksdb0468473/article/details/52126009

  2. 转:android service总结

    1.Service的种类   按运行地点分类: 类别 区别  优点 缺点   应用 本地服务(Local) 该服务依附在主进程上,  服务依附在主进程上而不是独立的进程,这样在一定程度上节约了资源,另 ...

  3. 51nod 1273 旅行计划——思维题

    某个国家有N个城市,编号0 至 N-1,他们之间用N - 1条道路连接,道路是双向行驶的,沿着道路你可以到达任何一个城市.你有一个旅行计划,这个计划是从编号K的城市出发,每天到达一个你没有去过的城市, ...

  4. (计数器)NOIP模拟赛(神奇的数位DP题。。)

    没有原题传送门.. 手打原题QAQ [问题描述]     一本书的页数为N,页码从1开始编起,请你求出全部页码中,用了多少个0,1,2,…,9.其中—个页码不含多余的0,如N=1234时第5页不是00 ...

  5. How to duplicate a UIButton in Objective C?

    http://stackoverflow.com/questions/1092875/how-to-duplicate-a-uibutton-in-objective-c 1down vote To ...

  6. Linux之epoll详细解析实现

    /* * fs/eventpoll.c (Efficient event retrieval implementation) * Copyright (C) 2001,...,2009 Davide ...

  7. linux内存管理2:内存映射和需求分页(英文名字:demand Paging,又叫:缺页中断)【转】

    转自:http://blog.csdn.net/zhangxinrun/article/details/5873148 当某个程序映象开始运行时,可执行映象必须装入进程的虚拟地址空间.如果该程序用到了 ...

  8. css3实现图片划过一束光闪过效果

    该效果在京东里的图片有. .img { display:block; position: relative; width:800px; height:450px; margin:0 auto; } . ...

  9. 开始gentoo之旅

    买了一台i7笔记本,dell 15游戏匣7559,老笔记本dell n4030装了gentoo. 用了两天,先用着,再慢慢学内核编译.

  10. 【linux高级程序设计】(第十二章)Linux多线程编程

    线程与进程对比 1.用户空间对比 2.内核空间资源对比 在创建线程时,Linux内核仍然创建一个新的PCB来标识这个线程.内核并不认为进程与线程有差别. 进程是操作系统管理资源的基本单元,线程时Lin ...