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

    我的理解,就是一种组合

    package com.test.pattern.decorator;
    
    //组件对象的接口,可以给这些对象动态地添加职责
    abstract class Component {
        public abstract void operation();
    }
    
    //具体组件
    class ConcreteComponent extends Component {
    
        @Override
        public void operation() {
            
        }
    }
    
    //装饰器接口,维持一个指向组件对象的接口对象, 并定义一个与组件接口一致的接口
    abstract class Decorator extends Component {
        
        /** 持有组件对象 */
        protected Component component;
        
        public Decorator(Component component) {
            this.component = component;
        }
        
        public void operation() {
            component.operation();
        }
    }
    
    //装饰器的具体实现对象
    class ConcreteDecoratorA extends Decorator {
        public ConcreteDecoratorA(Component component) { 
            super(component);
        }    
        
        private void operationFirst() {}
        private void operationLast() {}
        public void operation() {
            operationFirst();
            super.operation();
            operationLast();
        }
    }
    
    class ConcreteDecoratorB extends Decorator {
        public ConcreteDecoratorB(Component component) { 
            super(component);
        }    
        
        private void operationFirst() {}
        private void operationLast() {}
        public void operation() {
            operationFirst();
            super.operation();
            operationLast();
        }
    }
    
    public class Client {
        public static void main(String[] args) {
            Component c1 = new ConcreteComponent();
            Decorator decoratorA = new ConcreteDecoratorA(c1);  //给对象透明的增加功能A并调用  
            decoratorA.operation();
            Decorator decoratorB = new ConcreteDecoratorB(c1); //给对象透明的增加功能B并调用
            decoratorB.operation();
            Decorator decoratorBandA = new ConcreteDecoratorB(decoratorA);//装饰器也可以装饰具体的装饰对象,此时相当于给对象在增加A的功能基础上在添加功能B  
            decoratorBandA.operation();  
        }
    }

    ======================================================================================================================================================

     使用spring-data-redis替代mybatis默认二级缓存的时候,实际上就用到了装饰器模式,因为mytatis的缓存LoggingCache就是一种装饰器的设计。来看看怎么替换mybatis的默认二级缓存:

    一般来说可以实现Cache接口,但是采用装饰器设计模式的LoggingCache,才是我今天想要学习的,下面的代码只截取了重点

    /*** Eclipse Class Decompiler plugin, copyright (c) 2016 Chen Chao (cnfree2000@hotmail.com) ***/
    package org.apache.ibatis.cache.decorators;
    
    import java.util.concurrent.locks.ReadWriteLock;
    import org.apache.ibatis.cache.Cache;
    import org.apache.ibatis.logging.Log;
    import org.apache.ibatis.logging.LogFactory;
    
    public class LoggingCache implements Cache {
        private Log log;
        private Cache delegate;
        protected int requests = 0;
        protected int hits = 0;
    
        public LoggingCache(Cache delegate) {
            this.delegate = delegate;
            this.log = LogFactory.getLog(getId());
        }
    
        略
    }

    重点就是这个构造函数

    当我们继承它的时候,就可以使用自己传入的Cache实现:

    public class LoggingRedisCache extends LoggingCache {
    public LoggingRedisCache(String id) {
            super(new MybatisRedisCache(id));
        }
    }

    其中MybatisRedisCache是我们自己定义的,Cache的实现类

    ======================================================================================================================================================

    JAVA IO 实现就使用了装饰器模式,通过对JAVA IO 的深入了解,我突然觉得真正明白什么叫装饰器模式了,这里的装饰二字的含义。所谓装饰,就是子类不断的装饰自己的父类,通过装饰,一层一层,加添自己新的功能。

    InputStream是一个抽象类,JAVA IO可以分为两大类,一类是节点流,一类是过滤流。所谓节点流,就是直接操作数据源,比如FileInputStream和FileOutputStream就是节点流,他们直接操作文件;所谓过滤流,就是不直接操作文件,而是操作他们自己所持有的节点流,比如BufferedInputStream,ButfferedOutputStream,他们在自己内部分别持有了InputStream和OutputStream的引用对象,他们可以引用任何节点流,然后比如BufferedInputStream在read的时候,其实就是调用的inputStream的read(比如持有的这个对象实际引用的是FileInputStream,就是调用的FileinputStream的read),只不过在调用持有对象的read之前,先判断够不够buffer.length这么多,够了再一次读,避免频繁的读操作。实际上装饰器模式是很简单的,只是我之前一直看网上的代码,看的晕乎乎的,还是要看实际框架中的用法,才能有所收获

    哦 对了忘了说,区分节点流和过滤流最直接的方法,就是所有继承了FilterInoputStream/FilterOutputStream的都是过滤流

    另外还要说一些关闭过滤流,比如关闭ButfferedOutputStream的方式,看了它的源代码,它的close方法实际上包含两步,第一先flush一下,把缓存buffer里面的先写磁盘,第二部就直接把持有的outputstream给关闭,所以当我们使用ButfferedOutputStream的时候,是不需要手动关闭outputstream的,直接关闭ButfferedOutputStream就可以了

  • 相关阅读:
    《ElasticSearch6.x实战教程》之准备工作、基本术语
    《ElasticSearch6.x实战教程》正式推出
    【好书推荐】《剑指Offer》之硬技能(编程题12~16)
    synchronized凭什么锁得住?
    synchronized到底锁住的是谁?
    Java面试宝典(2020版)
    50道Redis面试题及答案整理,史上最全!
    MySQL面试题及答案整理,史上最全!
    Github 上优秀的 Java 项目推荐
    100道MySQL常见面试题总结
  • 原文地址:https://www.cnblogs.com/heben/p/5774760.html
Copyright © 2011-2022 走看看