Effective Java – Item 18 复合优先于继承

item18 · 复合优先于继承

此处继承不包括接口继承、包内部使用继承

继承打破了封装性

  • 子类依赖于父类的实现,父类变化时子类会遭破坏

    public class InstrumentedHashSet<E> extends HashSet<E> {
        private int addCount = 0;
        public InstrumentedHashSet(){
            
        }
        
        public InstrumentedHashSet(int initCap,float loadFactor) {
            super(initCap,loadFactor);
        }
    
        @Override
        public boolean add(E e) {
            addCount += 1;
            return super.add(e);
        }
    
        @Override
        public boolean addAll(Collection<? extends E> c) {
            addCount += c.size();
            return super.addAll(c);
        }
        
        public int getAddCount() {
            return addCount;
        }
    }
    
    InstrumentedHashSet<String> s = new InstrumentedHashSet<>();
    s.addAll(List.of("Snap", "Crackle", "Pop"));
    System.out.println(s.getAddCount()); // 6
    

    ​ 对于这个结果的期望输出值是3,可实际上返回了6。

    ​ 因为在 HashSet 内部, addAll 方法是基于它的 add 方法来实现的,即使 HashSet 的文档中没给出,但这也合理。

    ​ 当然我们可以把重写的 addAll 方法中的加法去掉,但父类的实现对子类并不透明,在不同的发行版中可能会被修改,这样得到的 InstrumentedHashSet 是非常脆弱的。

  • 即使只添加新方法,如果父类在以后的发行版增加了新方法,而且签名和自定义的方法一样会造成严重的冲突

复合

  • 通过复合(composition) 可以避免前面的所有问题

    public class InstrumentedSet<E> extends ForwardingSet<E> {
        private int addCount = 0;
    
        public InstrumentedSet(Set<E> s) {
            super(s);
        }
    
        @Override
        public boolean add(E e) {
            addCount += 1;
            return super.add(e);
        }
    
        @Override
        public boolean addAll(Collection<? extends E> c) {
            addCount += c.size();
            return super.addAll(c);
        }
    
        public int getAddCount() {
            return addCount;
        }
    }
    
    public class ForwardingSet<E> implements Set<E> {
        private final Set<E> s;
    
        public ForwardingSet(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);
        }
    
        @Override
        public Iterator<E> iterator() {
            return s.iterator();
        }
    
        @Override
        public Object[] toArray() {
            return s.toArray();
        }
    
        @Override
        public <T> T[] toArray(T[] a) {
            return s.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 int hashCode() {
            return s.hashCode();
        }
    
        @Override
        public boolean equals(Object obj) {
            return s.equals(obj);
        }
    
        @Override
        public String toString() {
            return s.toString();
        }
    }
    
    • InstrumentedSet 是一个包装类,也是修饰者模式
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值