美文网首页
设计模式系列 — 装饰模式

设计模式系列 — 装饰模式

作者: 一角钱技术 | 来源:发表于2020-10-24 23:51 被阅读0次

    点赞再看,养成习惯,公众号搜一搜【一角钱技术】关注更多原创技术文章。
    本文 GitHub org_hejianhui/JavaStudy 已收录,有我的系列文章。

    前言

    23种设计模式快速记忆的请看上面第一篇,本篇和大家一起来学习装饰模式相关内容。


    模式定义

    在不改变原有对象的基础上,将功能附加到对象上。

    动态的给一个对象添加一些额外的职责。就增加功能来说,装饰模式相比生成子类更为灵活。

    解决的问题

    扩展一个类的功能或给一个类添加附加职责。

    模式组成

    组成(角色) 作用
    抽象构件(Component) 给出一个抽象接口,以规范准备接收附加责任的对象
    具体构件(ConcreteComponent) 定义一个将要接收附加责任的类
    装饰角色(Decorator) 持有一个构件(Component)对象的实例,并定义一个与抽象构件接口一致的接口
    具体装饰角色(ConcreteDecorator) 负责给构件对象“贴上”附加的责任

    实例说明

    实例概况

    • 背景:隔壁老王创业准备开发一款视频软件
    • 冲突:调研市场发现有的用户需要自动添加美颜,有的需要自动添加滤镜
    • 解决方案:通过使用装饰模式在视频的基础上,能根据不同用户喜好添加相应功能

    使用步骤

    步骤1:定义Component抽象构件,也就是定义视频软件基础接口

    abstract class Component {
        //抽象的方法
        public abstract void operation();
    }
    

    Component是一个接口或者是抽象类,它定义了最核心的对象,也就是最原始的对象。

    步骤2:定义ConcreteComponent具体构件,也就是实现一个视频软件的基本功能

    class ConcreteComponent extends Component {
        @Override
        public void operation() {
            System.out.println("视频软件直播.");
        }
    }
    

    ConcreteComponent是最核心,最原始、最基本的接口或抽象类的实现,是我们要装饰的对象。

    步骤3:定义Decorator装饰角色,是抽象类,聚合了Component接口

    abstract class Decorator extends Component {
        private Component component=null;
    
        //通过构造函数传递被修饰者
        public Decorator(Component component){
            this.component=component;
        }
    
        //委托给被修饰者执行
        @Override
        public void operation() {
            this.component.operation();
        }
    }
    

    步骤4:具体装饰角色,A用户需要添加美颜功能

    class ConcreteDecoratorA extends Decorator {
    
        //定义被修饰者
        public ConcreteDecoratorA(Component component) {
            super(component);
        }
    
        //定义自己的修饰方法
        private void decorator(){
            System.out.println("添加美颜.");
        }
    
        @Override
        public void operation() {
            this.decorator();
            super.operation();
        }
    }
    

    步骤5:具体装饰角色,B用户需要添加滤镜功能

    class ConcreteDecoratorB extends Decorator {
    
        //定义被修饰者
        public ConcreteDecoratorB(Component component) {
            super(component);
        }
    
        //定义自己的修饰方法
        private void decorator(){
            System.out.println("添加滤镜.");
        }
    
        @Override
        public void operation() {
            this.decorator();
            super.operation();
        }
    }
    

    步骤6:给不同的用户在视频直播的时候添加不同的功能

    public class DecoratorPattern {
    
        public static void main(String[] args) {
            // 添加美颜
            Component componentA  = new ConcreteDecoratorA(new ConcreteComponent());
            componentA.operation();
    
            System.out.println();
    
            // 添加滤镜
            Component componentB  = new ConcreteDecoratorB(new ConcreteComponent());
            componentB.operation();
    
            System.out.println();
    
            // 添加美颜和滤镜
            Component component  = new ConcreteDecoratorA(new ConcreteDecoratorB(new ConcreteComponent()));
            component.operation();
        }
    
    }
    

    输出结果

    添加美颜.
    视频软件直播.
    
    添加滤镜.
    视频软件直播.
    
    添加美颜.
    添加滤镜.
    视频软件直播.
    

    优点

    • 不改变原有对象的情况下给一个对象扩展功能;
    • 使用不同的组合可以实现不同的效果;
    • 符合开闭原则

    缺点

    • 多层的装饰会使系统比较复杂。

    即一个实现类的功能若用多个装饰类进行装饰,则会增加该实现类的耦合度。

    应用场景

    扩展一个类的功能或给一个类添加附加职责。

    源码中的应用

    # JDK
    FilterInputStream
    
    #Servlet Api:
    javax.servlet.http.HttpServletRequestWrapper
    javax.servlet.http.HttpServletResponseWrapper
    

    FilterInputStream IO源码分析

    IO源码结构与装饰模式分析
    • InputStream :相当于我们装饰模式中类图的Component
    • FileInputStream :继承自InputStream,是具体构建的角色;
    • FilterInputStream :继承自InputStream,相当于类图中的Decorator角色,
    • DataInputStream :继承自FilterInputStream,是具体的修饰角色。

    FilterInputStream(装饰类)

    public class FilterInputStream extends InputStream {
        //持有的被装饰者对象
        protected volatile InputStream in;
        //初始化的时候就指定被装饰者
        protected FilterInputStream(InputStream in) {
            this.in = in;
        }
        //被装饰者方法的调用
        public int read() throws IOException {
            return in.read();
        }
     }
    
    

    DataInputStream(具体的装饰类)

    public class DataInputStream extends FilterInputStream implements DataInput {
    
        //构造器:指定被修饰者
        public DataInputStream(InputStream in) {
            super(in);
        }
        
        //扩展的功能,即修饰
        public final void readFully(byte b[], int off, int len) throws IOException {
            if (len < 0)
                throw new IndexOutOfBoundsException();
            int n = 0;
            while (n < len) {
                int count = in.read(b, off + n, len - n);
                if (count < 0)
                    throw new EOFException();
                n += count;
            }
        }
        
        public final char readChar() throws IOException {
            int ch1 = in.read();
            int ch2 = in.read();
            if ((ch1 | ch2) < 0)
                throw new EOFException();
            return (char)((ch1 << 8) + (ch2 << 0));
        }
    }
    

    方法中的调用

    在方法中调用方式和装饰模式调用类似。

    DataInputStream dis = new DataInputStream(new FileInputStream("/usr/local/temps/1.txt"));
    

    PS:以上代码提交在 Githubhttps://github.com/Niuh-Study/niuh-designpatterns.git

    文章持续更新,可以公众号搜一搜「 一角钱技术 」第一时间阅读, 本文 GitHub org_hejianhui/JavaStudy 已经收录,欢迎 Star。

    相关文章

      网友评论

          本文标题:设计模式系列 — 装饰模式

          本文链接:https://www.haomeiwen.com/subject/exkgmktx.html