装饰者模式

通过对已有类的包装,使新类在增加功能的同时,实现对已有类的复用。

装饰者模式 实现代码复用较 继承的优点:

  • 在类之间没有明确的is-a关系的提前下 利用继承,后续代码维护较难。例 Duck extends Bird ,虽然Duck目前 完全可以复用 Bird中的方法eat, drink, 然而后期需要为Bird添加 fly() 方法时,Duck 就自然而然的继承了这个不该有的方法,so Duck被污染了。所以,切记不用为了一时的偷懒,强行利用继承复用非is-a的类
public class Bird {
     eat();
     drink()
}
  • 继承会在一定程度上 破坏类的封装性。子类依赖于 父类的实现细节
import java.util.Collection;
import java.util.HashSet;
public class InstrumentHashSet<E> extends HashSet<E> {
    private int addCount = 0;

    public InstrumentHashSet() {
    }

    public InstrumentHashSet(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;
    }
}
import java.util.Arrays;
public class HelloTest {
    public static void main(String[] args) {
        InstrumentHashSet<String> s = new InstrumentHashSet<String>();
        s.addAll(Arrays.asList("the", "one", "two"));
        System.out.println(s.getAddCount());
    }
}

猜猜输出为多少
|
|
|
|
|
|
|
|
|
|
6
你以为super.addAll(c) 在实现有超类方法一次调用完成,然而实现 细节上 超类的addAll 通过调用 add来完成。
跟踪一下代码:
(InstrumentHashSet) addAll —> AbstractCollection addAll

 public boolean addAll(Collection<? extends E> c) {
        boolean modified = false;
        for (E e : c)
            if (add(e))     // 此处3次调用 实现类InstrumentHashSet 的 add
                modified = true;
        return modified;
    }

从而addCount 在addAll 中+3 一次,在add中 +1 三次,所以为6.

由于继承依赖于细节,所以我们需要对超类的实现细节有一定认识才能避免错误。如下对比相对傻瓜一些的包装类实现(只需关心 原有类提供的接口与输出,不会关注实现细节)

import java.util.Collection;
import java.util.HashSet;

public class WrapperHashSet<E> {
    private HashSet<E> hashSet;
    private int acount = 0;

    public WrapperHashSet(HashSet<E> hashSet) {
        this.hashSet = hashSet;
    }

    public void add(E e) {
        acount++;
        hashSet.add(e);
    }

    public void addAll(Collection<? extends E> list) {
        acount += list.size();
        hashSet.addAll(list);
    }
}

如上WrapperHashSet 在 实现add, addAll分别用hashSet来调用实现,自身并不参与细节实现。

你可能感兴趣的:(设计模式,装饰者模式)