zoukankan      html  css  js  c++  java
  • EffectiveJava(16)复合优先于继承

    为什么复合优先于继承?
    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));

    同样,继承也有使得功能复杂的类传播性更好,那么我们该何时使用继承呢
    当子类真正是超类的子类型的时候,可以使用继承

  • 相关阅读:
    2020暑假牛客多校9 B
    2020暑假牛客多校10 C -Decrement on the Tree (边权转点权处理)
    HDU 5876 补图的最短路
    CSP初赛复习
    遗传算法
    排列组合
    和式 sigma的使用
    多项式的各种操作
    三分
    NOIP2018普及游记
  • 原文地址:https://www.cnblogs.com/qwop/p/6637297.html
Copyright © 2011-2022 走看看