EffectiveJava学习笔记10:复合优先于继承,设置继承的注意点

复合优先于继承

1.复合和继承的概念

继承:实现继承(当一个类扩展另一个类的时候)

复合:不扩展现有的类,而是在新的类中增加一个私有域,引用现有类的一个实例。

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

包装类:复合实例包装起来的实例的类

2.继承的缺点

子类继承父类时,子类可以重写父类的任意方法,打破了封装性(final等措施除外),因此继承用于包内部是安全的,但是用于跨越包边界的继承是危险的。

3.复合的优点

将现有类变成新类的一个组件(复合)

新类中的每个实例方法都可以调用现有类实例中的对应的方法(转发)(新类中的方法称为转发方法)

这样的类不依赖现有类的实现细节,现有类添加新方法,也不会影响新的类

//转发类
public class FowardSet<E> implements Set<E> {  

    //引用现有类的实例,增加私有域(复合)
    private final Set<E> s;

    public FowardSet(Set<E> s){
        this.s= s;
    }


    /*
     *转发方法
     */
    @Override
    public int size() {
        return s.size();
    }

    @Override
    public boolean isEmpty() {
        return s.isEmpty();
    }

    @Override
    public boolean contains(Object o) {
        return s.contains(o);
    }

    @NotNull
    @Override
    public Iterator<E> iterator() {
        return s.iterator();
    }

    @NotNull
    @Override
    public Object[] toArray() {
        return s.toArray();
    }

    @NotNull
    @Override
    public <T> T[] toArray(T[] a) {
        return set.toArray(a);
    }

    @Override
    public boolean add(E e) {
        return s.add(e);
    }

    @Override
    public boolean remove(Object o) {
        return s.remove(o);
    }

    @Override
    public boolean containsAll(Collection<?> c) {
        return s.containsAll(c);
    }

    @Override
    public boolean addAll(Collection<? extends E> c) {
        return s.addAll(c);
    }

    @Override
    public boolean retainAll(Collection<?> c) {
        return s.retainAll(c);
    }

    @Override
    public boolean removeAll(Collection<?> c) {
        return s.removeAll(c);
    }

    @Override
    public void clear() {
        s.clear();
    }

    @Override
    public boolean equals(Object obj) {
        return s.equals(obj);
    }

    @Override
    public String toString() {
        return s.toString();
    }

    @Override
    public int hashCode() {
        return s.hashCode();
    }
}

/*
 * 包装类(wrapper class),采用装饰者模式
 */
public class InstrumentedSet<E> extends FowardSet<E> {
    private int addCount=0;

    public InstrumentedSet(Set<E> set) {
        super(set);
    }

    @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;
    }
}

上面是书中的一个复合案例,他新增了一个类-转发类(FowardSet<E>),内部增加了私有域,并引用实例s(复合),然后再让包装类,也就是继承中的子类来继承使用。

简单来讲就是讲继承的子类上面,作为新类实例中一个组成部分来重写。(类似子类相当于发动机,转发类相当于车子,子类变成其中一部分,而不是完全相当于父类了)

设置继承的注意点

1.设计继承时,提供文档说明,要么禁止继承

2.文档说明必须有说明可覆盖的方法的自用性:

说明每个共有或受保护的方法,调用了哪些可覆盖的方法,以什么顺序调用,调用结果的影响等。

3.发布继承类(超类)之前,必须编写子类对父类进行测试(一般是3个子类左右进行测试)

4.   在超类中,不要在覆盖器调用可被覆盖的方法,因为之后子类中它重写该方法,那么初始化构造时,一开始还是会调用超类的原生可被覆盖方法。会出错。

5.对于并非要进行子类化的类,最好要编写禁止子类化:

1.声明类为final         

2.将构造器都变成私有的,并增加公有的静态工厂代替构造器。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值