装饰者模式

Posted youxin2012

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了装饰者模式相关的知识,希望对你有一定的参考价值。

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

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

  • 在类之间没有明确的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来调用实现,自身并不参与细节实现。

以上是关于装饰者模式的主要内容,如果未能解决你的问题,请参考以下文章

装饰者模式

装饰者模式

设计模式装饰者模式

设计模式学习_装饰者模式

设计模式整理_装饰者模式

设计模式 - 装饰者模式详解