装饰模式

​ Decorator Pattern:属于GoF23种设计模式中结构型设计模式的一种,又被称为装饰者模式。

​ 简单的说,装饰模式/装饰者模式就是给一个现有的类,在不改变这个类的情况下,动态的给这个类进行扩展,添加新的东西,比如说添加新的功能。

动态的意思也就是说不需要这个类创建的时候指定,完全可以等这个类创建完成了之后,已经完全成为了一个“活蹦乱跳”的对象了之后,再给他添加新的东西,不需要写死,而是想要什么时候加就什么时候加,想要加什么就加什么。

结构

  • 给出一张简易的装饰者模式的结构图片吧,分析一下下

    1. 有一个抽象对象,这个是干什么的呢?这个是被装饰者对象,简单的说就是我们需要在这个对象上进行装饰,这样就好理解了吧。

      至于为什么要对被装饰者进行抽象,因为要面向接口编程的嘛,也可以留出更大的扩展空间不是。

    2. 紧接着的就是具体的对象了,也就是真实的被装饰者。

    3. 装饰者模式主要的还是装饰,那么显然对于装饰的抽象是不可避免的,也不会就有一个功能需要装饰的吧,如果真的有那也要进行抽象以下,毕竟,也需,过不了多久你的PM和你说需求要改了呢?

      这个里面需要注意的就是维护了一个被装饰者对象,因为在实际的代码中我们应该对这个被装饰者进行包装,但是前提是我们不能修改这个被装饰者,也就是需要动态两个字的体现,具体的应用可以看后面的代码部分可能会好理解一点。

    4. 下面的就是所有的具体如何去装饰的实现类了。

举例说明

  1. 对于装饰着模式来说,最容易体会到的,那就是学习JAVA的IO流的时候了,那里面的一层层的包装,真的是眼花缭乱。

    比如想要生成一个字符缓冲流,应该如何???

    BufferedReader stringBuffer = new BufferedReader(new InputStreamReader(new FileInputStream("demo.txt")));
    

    哈哈,这就是层层装饰啊,从一个文本输入流,变成字符串输入流,变成带缓冲的字符缓冲流。

  2. OK,我们也可以面向生活一点儿,有没有小伙伴知道“加码子”是啥意思啊?早餐的时候,首先呢点了一碗素面,发现不行,太过于单调,有点了一个豆干,还是不行,紧接着一个鸡蛋,还是不行,有加了一份牛肉…越来越多,越来越多,原先的一碗素面已经是“五彩缤纷”了啊。

  3. 再来个小栗子,也是阔以的啊,比如去喝个奶茶,有原味奶茶的吧,但是没意思啊,味道不好,但是呢,我们可以加东西进去啊,珍珠或者椰果?加冰或者不加冰?都是可以的嘛

  4. 用笔者自己喜欢的方式的话,那就是游戏里面人物的时装了,想当初,毒奶粉的时候,笔者为了黄金天空套,又不想充钱,那是天天搬砖,天天搬砖换代币卷,一件一件凑齐的啊,看着自己的角色一件件穿上时装,嘿嘿装饰模式之下变得金闪闪啊(不是那个金闪闪啊,这里可没有咖喱棒)。

注意

  1. 其实呢这个装饰模式的结构是可以简化的,上面给出的是一个完整的结构。可以简化的部分很显然嘛,就是两个抽象类可以去掉撒。

    也就是说,只有一个被装饰者对象的时候,被装饰者的抽象类咱就不要了,抽象装饰直接继承这个对象就成了啊。

    还有一种呢就是只有一个具体的装饰实现类,那就直接不要抽象装饰类就行了呗,子类是可以顶替父类的嘛。

  2. 装饰着的优点的话,应该就是可以创建五花八门的各种各样的实际对象吧。这样子显得扩展更加的灵活,而且自由性很高很高的。

  3. 但是捏,东西虽好,也是不可以乱用的,可以看到这个位置有两个大分支线也就是两个抽象类的部分了,如果东西一多,那产生的小小的子类,估计可以看的你头疼…

一个小DEMO

  1. 场景

    一个简单的场景设计吧,记得那是一天下午,压马路的笔者看到了路边的奶茶店,正好口渴准备去点一杯,可是面前的价目表看的真的是眼花缭乱啊,只好准备自己搭配一个,嘿嘿,来一杯原味奶茶,加上椰果,加上冰,珍珠嘛,还是不需要了吧。

    用代码模拟一下这个场景的实现吧!

    抽象类还是接口,那就看大家的习惯吧。

  2. 首先定义被装饰者对象——奶茶的话,估摸着算是饮料???

    package com.decorator;
    /*** 装饰者模式——抽象对象——也就是被装饰者对象的抽象对象* DEMO中的话就是饮料了* @author WQ*/
    public abstract class Drinks {public abstract void show();
    }
    
  3. 来个奶茶类,这就是具体的被装饰者对象了!

    package com.decorator;
    /*** 装饰者模式——具体的被装饰者对象* DEMO中的话就是奶茶了* @author WQ*/
    public class MilkyTea extends Drinks{@Overridepublic void show() {System.out.println("我是一杯奶茶啊!");}
    }
    
  4. 定义个抽象的装饰类,这里的话抽象起来,算作配料???

    package com.decorator;
    /*** 装饰者模式——抽象装饰对象* DEMO中的话就是配料吧* @author WQ*/
    public abstract class Batching extends Drinks{/*** 维护一个被装饰着对象* (这里是面向接口编程)* 注意权限修饰符是protected 这个类的子类是可以直接使用的*/protected Drinks drink;/*** 说明一下下* 抽象类是可以有构造方法的* 只是不能直接创建抽象类的实例对象而已* @param drink*/public Batching(Drinks drink) {this.drink = drink;}@Overridepublic void show() {drink.show();}
    }
    
  5. 真实的配料也需要上场了啊,这部分就是具体的装饰类了。

    package com.decorator;
    /*** 装饰者模式——具体装饰类对象* 这是珍珠哦* @author WQ*/
    public class Pearl extends Batching{/*** 自然的需要维护一个被装饰者对象的嘛* @param drink*/public Pearl(Drinks drink) {super(drink);}/*** 这里还需要覆盖掉父类的方法* 父类里面只是对被装饰着对象调用了一下,* 我们需要装饰啊*/@Overridepublic void show() {/*** 这里首先是调用了父类的方法的* 我们是对原有的对象进行包装,* 那么应该保证的是原有对象的功能应该是完善的,* 如果这里不调用的话,那么我们编写出来的结果就没有被装饰的类了。*/super.show();decorate(drink);}/*** 这个位置就是具体的被装饰的逻辑了,* 虽然这里只有一个小小的输出,* 但是实现更为复杂的逻辑的时候还是需要抽出来成为一个方法的*/private void decorate(Drinks drink) {System.out.print("加珍珠~");}
    }
    //--------------------------------------------------------------------
    package com.decorator;
    /*** 装饰者模式——具体装饰类对象* 这是椰果哦* @author WQ*/
    public class Coconut extends Batching{public Coconut(Drinks drink) {super(drink);}@Overridepublic void show() {super.show();decorate(drink);}private void decorate(Drinks drink) {System.out.print("加椰果~");}
    }
    //----------------------------------------------------------------
    package com.decorator;
    /*** 装饰者模式——具体装饰类对象* 这是冰哦* @author WQ*/
    public class Ice extends Batching{public Ice(Drinks drink) {super(drink);}@Overridepublic void show() {super.show();decorate(drink);}private void decorate(Drinks drink) {System.out.print("加冰~");}
    }
    
  6. 编个测试类

    package com.decorator;
    /*** 装饰者模式——测试类部分* @author WQ*/
    public class Main {public static void main(String[] args) {//被装饰者对象Drinks drink = new MilkyTea();//这一次来个全加Batching batching1 = new Pearl(drink);//注意传进去的参数不是drink了,而是被装饰了以后的对象了啊//对象已经被打包了,原来的对象穿了一套“衣服”了Batching batching2 = new Coconut(batching1);//这也是为啥装饰类也要继承被装饰类的原因哦Batching batching3 = new Ice(batching2);batching3.show();System.out.println();//换个我们熟悉的方式的Batching batching = new Ice(new Pearl(new MilkyTea()));batching.show();}
    }
    
  7. 测试结果

    我是一杯奶茶啊!
    加珍珠~加椰果~加冰~
    我是一杯奶茶啊!
    加珍珠~加冰~
    

完成!

加糖加冰加牛奶——装饰模式相关推荐

  1. 计算机弹奏卡布奇诺,计算机学院信息安全技术协会卡布奇诺加糖队在第十二届全国大学生信息安全竞赛中喜获佳绩...

    7月27号,第十二届全国大学生信息安全竞赛--创新实践能力赛在电子科技大学圆满结束.我校信息安全技术协会卡布奇诺实验室派出2支队伍参加本次竞赛,并在指导老师刘朝晖的精心指导下获得全国三等奖的好成绩. ...

  2. torch tensor去掉1维_自制番茄酱,只加糖是不对的,牢记1点技巧,番茄酱沙甜更好吃...

    导语:家常自制番茄酱,10分钟做3瓶,无添加更放心,沙甜好吃还健康 番茄自带酸甜的口感,深得家里大小朋友的喜欢,当然了番茄酱更是我家中不可少的,做菜的时候加上点番茄酱,孩子吃饭便能特别香,以往我经常会 ...

  3. 【亲测可用→防止入坑Routes】设置angular10项目异步加载、惰性加载、懒加载路由

    创建一个带路由的项目,依次执行下面每行代码 ng n RouingApp --routingcd RouingAppng g c components/firstng g c components/s ...

  4. 照片墙瀑布流加载与阻止加载

    网上大部分主流的瀑布流应用基本都是由后端在提供图片地址的同时提供图片宽高,这样,前端不必等待图片渲染完成,可以根据图片的宽高先把装载图片的容器或父节点先放上页面,完成基础性的布局,再让图片以渐变或其他 ...

  5. webpack v3 结合 react-router v4 做 dynamic import — 按需加载(懒加载)

    为什么要做dynamic import? dynamic import不知道为什么有很多叫法,什么按需加载,懒加载,Code Splitting,代码分页等. 总之,就是在SPA,把JS代码分成N个页 ...

  6. javascript图片懒加载与预加载的分析

    懒加载与预加载的基本概念. 懒加载也叫延迟加载:前一篇文章有介绍:JS图片延迟加载 延迟加载图片或符合某些条件时才加载某些图片. 预加载:提前加载图片,当用户需要查看时可直接从本地缓存中渲染. 两种技 ...

  7. 基于jQuery的图片异步加载和预加载实例

    如今的网页中有很多图片,比如相册列表,那么如果一次性读取图片将会瞬间加重服务器的负担,所以我们用jQuery来实现图片的异步加载和预加载功能,这样在页面的可视范围内才会加载图片,当拖动页面至可视界面时 ...

  8. 【Android 逆向】加壳技术识别 ( 函数抽取 与 Native 化加壳的区分 | VMP 加壳与 Dex2C 加壳的区分 )

    文章目录 一.加壳特征识别 1.函数抽取 与 Native 化加壳的区分 2.VMP 加壳与 Dex2C 加壳的区分 一.加壳特征识别 1.函数抽取 与 Native 化加壳的区分 函数抽取 与 Na ...

  9. 【Android 逆向】加壳技术简介 ( 动态加载 | 第一代加壳技术 - DEX 整体加固 | 第二代加壳技术 - 函数抽取 | 第三代加壳技术 - VMP / Dex2C | 动态库加壳技术 )

    文章目录 一.动态加载 二.第一代加壳技术 ( DEX 整体加固 ) 三.第二代加壳技术 ( 函数抽取 ) 四.第三代加壳技术 ( Java 函数 -> Native 函数 ) 五.so 动态库 ...

最新文章

  1. i7 7代 linux,【Intel 酷睿i7 7代(移动版)参数】Intel 酷睿i7 7代(移动版)系列CPU参数-ZOL中关村在线...
  2. Java编程的逻辑 (29) - 剖析String
  3. 【springboot】【若依(ruoyi)】@RestController 接口跨域请求
  4. 把 LiveData 用于事件传递那些坑
  5. UVALive 6885 Flowery Trails 最短路枚举
  6. 案例分析:你造吗?有个ORA-60死锁的解决方案
  7. shell实战训练营Day2
  8. Vscode配置ftp连接远程服务器
  9. 刘汝佳Dijkstra模板
  10. servlet生成验证码和点击刷新验证码
  11. Android基于百度OCR识别图片中的文字
  12. 工程制图与计算机绘图知识点总结,工程制图与计算机绘图-西安电子科技大学.PDF...
  13. 网易的爆款密码,藏在Q3财报里
  14. java程序设计高级教程答案_Java高级程序设计实战教程答案
  15. 1101 -- 正弦和余弦
  16. 同一设备安装不同版本的Vue脚手架
  17. 服务器信号有杂音怎么回事,麦克风有杂音或电流声等的解决方法
  18. 02325计算机系统结构ppt,02325计算机系统结构2009
  19. Coremail2021邮件安全竞赛正式开幕!快来报名吧!
  20. xml在u3d的使用[u3d_rpg游戏开发之物品管理(四)]

热门文章

  1. HTPP详解(真的很经典)
  2. CS1703 C# Multiple assemblies with equivalent xxx... and. Remove one of the duplicate references.
  3. C++ API设计笔记
  4. 再谈宋星博客的留言与seo培训联盟
  5. 使用C语言绘制一个笑脸smile
  6. Python初学笔记2-【循环语句】
  7. 百度云不限速-proxyee-down
  8. 程序员如何优雅地写公众号
  9. 拉了300M的网,下载速度为啥还是这么慢?计算机基础(五)之网络层完结
  10. 台式计算机摄像头怎么打开,如何打开摄像头,教您Win7摄像头怎么打开