• 装饰器设计模式


    通俗的讲装饰器就是在不改变对象结构的前提下,扩充对象的功能。

        下面以effective java中例题   

               问题  我想扩充Hash<set>功能,使得能够统计添加过元素的个数?

            或许你可能会自定义一个类通过继承扩展,从而实现计数功能,代码如下:

              

    package com.effectJava.Chapter2;
    
    import java.util.Arrays;
    import java.util.Collection;
    import java.util.HashSet;
    
    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++;
            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 static void main(String... args) {
            InstrumentedHashSet s = new InstrumentedHashSet<String>();
            s.addAll(Arrays.asList("shape", "Crackle", "Pop"));
            System.out.println(s.getAddCount());
        }
    }
    

      上面代码直接继承hashSet类,然后覆盖 add和addAll方法 ,你会发现最终结果不是3,而是6,其实addAll内部实现是通过调用add,可能你又想到可以通过删除addAll方法上的 标志删除的那行代码,通过上述操作确实能够实现功能,但是这种功能的实现的子类比较脆弱,如果父类增加新方法,或者原方法有改动,都可能导致统计失败。

       为此我们提出装饰器设计模式,  通过被装饰者和装饰者之间的互相调用来实现扩展技术功能的目的。

          首先定义一个装饰器基类ForwardingSet<E> 实现Set<E>接口,由于add和addAll方法都在Set接口中定义,因此可以通过实现此接口定义装饰器

    package com.effectJava.Chapter2;
    
    import java.util.Collection;
    import java.util.Iterator;
    import java.util.Set;
    
    //装饰器
    public class ForwardingSet<E> implements Set<E> {
    
        private final Set<E> set;
        public ForwardingSet(Set<E> set) {
            this.set = set;
        }
    
        @Override
        public int size() {
            return set.size();
        }
    
        @Override
        public boolean isEmpty() {
            return set.isEmpty();
        }
    
        @Override
        public boolean contains(Object o) {
            return set.contains(o);
        }
    
        @Override
        public Iterator<E> iterator() {
            return set.iterator();
        }
    
        @Override
        public Object[] toArray() {
            return set.toArray();
        }
    
        @Override
        public <T> T[] toArray(T[] a) {
            return set.toArray(a);
        }
    
        @Override
        public boolean add(E e) {
            return set.add(e);
        }
    
        @Override
        public boolean remove(Object o) {
            return set.remove(o);
        }
    
        @Override
        public boolean containsAll(Collection<?> c) {
            return set.containsAll(c);
        }
    
        @Override
        public boolean addAll(Collection<? extends E> c) {
            return set.addAll(c);
        }
    
        @Override
        public boolean retainAll(Collection<?> c) {
            return set.retainAll(c);
        }
    
        @Override
        public boolean removeAll(Collection<?> c) {
            return set.removeAll(c);
        }
    
        @Override
        public void clear() {
            set.clear();
        }
    }
    

      定义一个装饰器类

    package com.effectJava.Chapter2;
    
    import java.util.*;
    
    //具体的装饰器类
    //装饰对象可以在转发这些请求以前或以后增加一些附加功能,这样就可以确保了在运行时,不用修改给定对象的结构就可以在外部增加附加的功能。
    //在面向对象的设计中,通常通过继承来事项对给定类的功能扩展。
    public class InstrumentedSet<E> extends ForwardingSet<E> {
    
        private  int CountSize=0;
        public InstrumentedSet(Set<E> set) {
            super(set);
        }
        @Override
        public boolean addAll(Collection<? extends E> c) {
            CountSize += c.size();
            return super.addAll(c);
        }
    
        @Override
        public boolean add(E e) {
            CountSize++;
            return super.add(e);
        }
    
        public int getCountSize() {
            return CountSize;
        }
    
      }
    

      定义一个被装饰者(这里我们直接用HashSet因为它实现类Set<E>,避免我们自己取实现)

     public static void main(String... args) {
    //        HashSet是被装饰者, InstrumentedSet是装饰者
            InstrumentedSet<String> s = new InstrumentedSet<String>(new HashSet<String>());
            s.addAll(Arrays.asList("1", "2", "3"));
            System.out.println(s.getCountSize());//结果为3
        }
    

      总结   其实装饰器基类中有一个变量保存被装饰器类对象,装饰器和被装饰器的功能扩展是基于两者都实现相同的接口,即类型相同,然后可以互相发送消息,扩展功能。

          

  • 相关阅读:
    [Web Security] Create a hash salt password which can stored in DB
    [Angular] Stagger animation v4.3.3
    [D3] Make D3 v4 Charts Responsive with the viewBox attribute
    [D3] Create Chart Axes with D3 v4
    [D3] Margin Convention with D3 v4
    [D3] Better Code Organization with selection.call() with D3 v4
    [D3] Basic Interactivity with D3 v4
    [Angular] Reactive Store and AngularFire Observables
    Google Play和基于Feature的过滤
    Three Swaps DFS
  • 原文地址:https://www.cnblogs.com/09120912zhang/p/8290281.html
Copyright © 2020-2023  润新知