• 结构性设计模式之装饰器模式


    装饰器模式

    概述

    装饰器模式(Decorator Pattern)也称为包装模式(Wrapper Pattern),属于结构型模式。

    它是指在不改变原有对象的基础之上,允许向一个现有的对象添加新的功能,同时又不改变其结构,作为现有的类的一个包装。

    这种模式创建一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。

    提供了比继承更有单性的替代方案,进行扩展原有对象的功能。

    装饰器模式的核心是功能扩展。使用装饰器模式可以透明且动态地扩展类的功能。

    装饰器模式主要用于诱明且动态地扩展类的功能。

    实现原理

    让装饰器实现被包装类相同的接口,使得装饰器与被扩展类类型一致,并在构造函数中传入该接口对象,然后就可以在接口需要实现的方法中在被包装类对象的现有功能上添加新功能。

    由于装饰器与被包装类属于同一类型,且构造函数的参数为其实现接口类,因此装饰器模式具备嵌套扩展功能,因此就能使用装饰器模式一层层的对最底层被包装类进行功能扩展。

    在JDK中,IO相关包下大量使用装饰器模式,如BufferedReader、InputStream、OutputStream等类

    主要角色

    装饰器模式主要包含4种角色

    1.抽象组件(Component)

    抽象组件可以是一个接口或者抽象类,其充当被装饰类的原始对象,规定了被装饰对象的行为。

    2.具体组件(ConcreteComponent)

    具体组件实现/继承抽象组件的一个具体对象,即被装饰对象。

    3.抽象装饰器(Decorator)

    通用的装饰具体组件的装饰器,其内部必然有一个属性指向抽象组件;其实现一般是一个抽象类,主要是为了让其子类按照其构造形式传入一个抽象组件,这是强制的通用行为。

    如果系统中装饰逻辑单一,并不需要实现许多装饰器,那么可以直接省略该类,而直接实现一个具体装饰器即可。

    4.具体装饰器(ConcreteDecorator)

    抽象装饰器的具体实现类,理论上,每个具体组件都扩展了抽象组件对象的一种功能。

    应用场景

    1.用于扩展一个类的功能或给一个类添加附加职责。
    
    2.动态的给一个对象添加功能,这些功能可以再动态的澈销。
    
    3.需要为一批的兄弟类进行改装或加装功能。
    
    • 1
    • 2
    • 3
    • 4
    • 5

    优缺点

    优点:

    1.装饰器是继承的补充,比继承灵活,不改变原有对象的情况下动态地给一个对象扩展功能,即插即用。
    
    2.装饰器完全遵守开闭原则。
    
    • 1
    • 2
    • 3

    缺点:

    1.会出现更多的代码,更多的类,增加程序复杂性。
    
    2.通过使用不同装饰类以及这些装饰类的排列组合,可以实现不同效果。
    
    3.动态装饰时,多层装饰时会更复杂。
    
    • 1
    • 2
    • 3
    • 4
    • 5

    装饰器模式的基本使用

    创建抽象组件

    创建Phone抽象类

    public abstract class Phone {
        public abstract String call();
        public abstract double price();
    }
    
    • 1
    • 2
    • 3
    • 4

    具体组件

    创建最基本具有打电话功能的手机

    public class BasePhone extends Phone {
        @Override
        public String call() {
         return "BasePhone call";
        }
    
        @Override
        public double price() {
            return 0.1;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    抽象装饰器

    创建一个抽象装饰器来扩展该只具备基本功能的手机

    public abstract class PhoneDecorator extends Phone {
        private Phone phone;
    
        public PhoneDecorator(Phone phone) {
            this.phone = phone;
        }
    
        @Override
        public String call() {
            return phone.call();
        }
    
        @Override
        public double price() {
            return phone.price();
        }
    
        /**
         * 扩展功能
         */
        public abstract void sendMsg();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    具体装饰器

    public class SatellitePhoneDecorator extends PhoneDecorator{
        public SatellitePhoneDecorator(Phone phone) {
            super(phone);
        }
    
        public void sendMsg() {
            System.out.println("PhoneCallDecorator sendMsg");
        }
    
        @Override
        public String call() {
            return  "SatellitePhone call";
        }
    
        @Override
        public double price() {
            return super.price()+100;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    客户端调用

        public static void main(String[] args) {
            // 创建需要被装饰的原始对象(即要被装饰的对象)
            Phone phone = new BasePhone();
            System.out.println("使用: "+phone.call()+" 方式打电话,每分钟单价:" + phone.price());
    
            // 给对象透明的增加额外功能并调用
            PhoneDecorator phoneDecorator = new SatellitePhoneDecorator(phone);
            System.out.println("使用: "+phoneDecorator.call()+" 方式打电话,每分钟单价:" + phoneDecorator.price());
    
            // 装饰器也可以装饰具体的装饰对象,相当于给对象在增加的功能基础上在添加功能,这里体现在单价100.1基础上再+100
            PhoneDecorator satellitePhoneDecorator = new SatellitePhoneDecorator(phoneDecorator);
            System.out.println("使用: "+satellitePhoneDecorator.call()+" 方式打电话,每分钟单价:" + satellitePhoneDecorator.price());
            satellitePhoneDecorator.sendMsg();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    使用: BasePhone call 方式打电话,每分钟单价:0.1
    使用: SatellitePhone call 方式打电话,每分钟单价:100.1
    使用: SatellitePhone call 方式打电话,每分钟单价:200.1
    PhoneCallDecorator sendMsg
    
    • 1
    • 2
    • 3
    • 4
  • 相关阅读:
    Protobuf的使用,结合idea
    七. 镜头知识之像圈与sensor感光面积
    逐步学习 Swagger enum:从入门到精通
    【环境配置】使用Docker搭建LAMP环境
    python利用BUG让它免费啦~你在不知道就要后悔啦~
    基于小脑模型神经网络轨迹跟踪matlab程序
    安装zip扩展(PHP)
    ”只用 1 分钟“ - 超简极速 Apk 签名 & 多渠道打包神器
    Python-可视化单词统计词频统计中文分词
    从这两道题重新理解,JS的this、作用域、闭包、对象
  • 原文地址:https://blog.csdn.net/qq_38628046/article/details/126131404