zoukankan      html  css  js  c++  java
  • 装饰器设计模式

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

        下面以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
        }
    

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

          

  • 相关阅读:
    通过Javascript调用微软认知服务情感检测接口的两种实现方式
    Microsoft Flow 概览
    使用PowerApps快速构建基于主题的轻业务应用 —— 进阶篇
    从三个语言(C++,Java,C#)的几个性能测试案例来看性能优化
    自己动手,打造轻量级VSCode/C#环境代替LinqPad
    2015年总结
    将知识变成你的技能点
    瞎子摸象与刻舟求剑
    俺的追求,下一个五年的指导纲领
    工作中任务管理的四个原则和四个技能
  • 原文地址:https://www.cnblogs.com/09120912zhang/p/8290281.html
Copyright © 2011-2022 走看看