Java设计模式 07-装饰者模式

装饰者模式

套娃模式,直接new放构造器里面套

把抽象类聚合到它的子类里 该子类(装饰者)构造抽象类的实现(被装饰者)

一、星巴克咖啡订单项目(咖啡馆)

1)咖啡种类/单品咖啡:Espresso(意大利浓咖啡)、ShortBlack、LongBlack(美式咖啡)、Decaf(无因咖啡)

2)调料:Milk、Soy(豆浆)、Chocolate

3)要求在扩展新的咖啡种类时,具有良好的扩展性、改动方便、维护方便

4)使用 OO 的来计算不同种类咖啡的费用: 客户可以点单品咖啡,也可以单品咖啡+调料组合。

二、方案 1-解决星巴克咖啡订单项目

image-20210628202524564

  • 问题分析

1)Drink 是一个抽象类,表示饮料

2)des 就是对咖啡的描述, 比如咖啡的名字

3)cost() 方法就是计算费用,Drink 类中做成一个抽象方法.

4)Decaf 就是单品咖啡, 继承 Drink, 并实现 cost

5)Espress && Milk 就是单品咖啡+调料, 这个组合很多

  • 问题

会有很多类,当我们增加一个单品咖啡,或者一个新的调料,类的数量就会倍增,就会出现类爆炸

三、方案 2-解决星巴克咖啡订单(好点)

前面分析到方案 1 因为咖啡单品+调料组合会造成类的倍增,因此可以做改进,将调料内置到 Drink 类,这样就不会造成类数量过多。从而提高项目的维护性(如图)

image-20210628202706388

说明: milk,soy,chocolate 可以设计为 Boolean,表示是否要添加相应的调料.

  • 问题分析

1)方案 2 可以控制类的数量,不至于造成很多的类

2)在增加或者删除调料种类时,代码的维护量很大

3)考虑到用户可以添加多份 调料时,可以将 hasMilk 返回一个对应 int

4)考虑使用装饰者模式

四、装饰者模式

1、定义

  • 1)装饰者模式:动态的将新功能附加到对象上。在对象功能扩展方面,它比继承更有弹性,装饰者模式也体现了开闭原则**(ocp**)
  • 2)这里提到的动态的将新功能附加到对象ocp 原则,在后面的应用实例上会以代码的形式体现,请同学们注意体会。

2、原理

  • 1)装饰者模式就像打包一个快递

主体:比如:陶瓷、衣服 (Component) // 被装饰者

包装:比如:报纸填充、塑料泡沫、纸板、木板(Decorator) //装饰者

  • 2)Component 主体:比如类似前面的 Drink
  • 3)ConcreteComponent 和 Decorator

ConcreteComponent:具体的主体, 比如前面的各个单品咖啡

  • 4)Decorator: 装饰者,比如各调料.
    在如图的 Component 与 ConcreteComponent 之间,如果 ConcreteComponent 类很多,还可以设计一个缓冲层,将共有的部分提取出来,抽象层一个类

image-20210628202922671

3、通过装饰者模式解决星巴克咖啡订单

先new 装饰者,把被装饰者放入装饰者的构造器中

image-20210628224950914

4、 装饰者模式下的订单:2 份巧克力+一份牛奶的 LongBlack

image-20210628203001231

5、装饰者模式咖啡订单项目代码演示

  • Drink抽象类
public abstract class Drink {
    public String desc;//描述
    public float price = 0.0f;//加个

    //计算费用的抽象方法
    //子类实现
    public abstract float cost();

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }

    public float getPrice() {
        return price;
    }

    public void setPrice(float price) {
        this.price = price;
    }
}

  • Decorator调味料类
public class Decorator extends Drink {

    private Drink drink;//聚合关系

    public Decorator(Drink drink) {
        this.drink = drink;
    }

    @Override
    public float cost() {
        //getPrice拿到自己的价格
        return super.getPrice()+drink.cost();
    }

    @Override
    public String getDesc() {
        //drink.getDesc() 被装饰者信息
        return getPrice()+drink.getPrice()+desc+drink.getDesc();
    }
}

  • Coffee
public class Coffee extends Drink {
    @Override
    public float cost() {
        return super.getPrice();
    }
}

  • Chocolate
public class Chocolate extends Decorator {
    public Chocolate(Drink drink) {
        super(drink);
        setDesc("巧克力");
        setPrice(3); //当前调味品价格
    }
}

  • Espresso
public class Espresso extends Coffee {
    public Espresso() {
        setDesc("Espresso");
        setPrice(6);
    }
}

  • LongBlack
public class LongBlack extends Coffee{
    public LongBlack() {
        setDesc("LongBlack");
        setPrice(10);
    }
}

  • Milk
public class Milk extends Decorator {
    public Milk(Drink drink) {
        super(drink);
        setDesc("牛奶");
        setPrice(2);
    }
}

  • ShortBlack
public class ShortBlack extends Coffee {
    public ShortBlack() {
        setDesc("shortblack");
        setPrice(5);
    }
}

  • Soy
public class Soy extends Decorator {
    public Soy(Drink drink) {
        super(drink);
        setDesc("豆浆");
        setPrice(1.5f);
    }
}

  • 主函数
public class Client {
    public static void main(String[] args) {
        Drink longBlack = new LongBlack();
        System.out.println(longBlack.getDesc());
        System.out.println(longBlack.getPrice());

        Milk milk = new Milk(longBlack);
        System.out.println(milk.getDesc());
        System.out.println(milk.getPrice());

        Chocolate chocolate = new Chocolate(milk);
        System.out.println(chocolate.getDesc());
        System.out.println(chocolate.getPrice());

        Chocolate chocolate1 = new Chocolate(chocolate);
        System.out.println(chocolate1.getDesc());
        System.out.println(chocolate1.getPrice());
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.kler.cn/a/8232.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Spring】2—IOC容器

⭐⭐⭐⭐⭐⭐ Github主页👉https://github.com/A-BigTree 笔记链接👉https://github.com/A-BigTree/Code_Learning ⭐⭐⭐⭐⭐⭐ 如果可以,麻烦各位看官顺手点个star~😊 如果文章对你有所帮助,可以点赞👍…

教你如何搭建物业-后勤管理系统,demo可分享

1、简介 1.1、案例简介 本文将介绍,如何搭建物业-后勤管理。 1.2、应用场景 该应用包含疫情上报、绿化、安保等管理功能。 2、设置方法 2.1、表单搭建 1)新建表单【返区登记】,字段设置如下: 名称类型名称类型姓名单行文本…

静态路由的原理和配置(理论详细实验全面)

第五章:静态路由 目录 第五章:静态路由 5.1路由器的工作原理 5.1.1路由器根据路由表转发数据 5.1.2 路由信息获取的方式 5.2路由选路原则 5.2.1最长匹配原则 5.2.2路由优先级 5.2.3路由度量值 5.3静态路由 5.3.1静态路由实验 5.3.2缺省路由实…

初学对象存储OSS---学习笔记

文章目录前言一、OSS是什么?下面以一个小故事介绍OSS的作用:二、怎么使用OSS1.进入 -----> [阿里云官网](https://www.aliyun.com/)2.点击进入OSS控制台3.获取accessKeyId 和 accessKeySecret4.拿到了accessKeyId 和 accessKeySecret ,就可…

CTP_将C++封装为Python可调用接口

目录 写在前面: 前置准备: step 1 与上期所原始代码对比分析源码 td源码 1 配置属性-》常规-》配置类型 要为 “动态库(.dll)” 2 VC目录 -》包含目录 3 VC目录 -》 库目录 4 链接器-》常规-》附加库目录 5 链接器-》输入-》附加依赖项 vnctp.h 的功…

CTF杂项提纲

CTF的杂项是涉及编码,图片隐写,音频隐写,压缩包分析的方向,本文对MISC的知识点做了一个简单列举 常见编码 ASCII 0-9,48-57 A-Z 65-90 a-z 97-122 URL url编码又叫百分号编码,是统一资源定位的编码方式 base16/…

leetcode每日一题:数组篇(1/2)

😚一个不甘平凡的普通人,日更算法学习和打卡,期待您的关注和认可,陪您一起学习打卡!!!😘😘😘 🤗专栏:每日算法学习 💬个人…

cmake 常用方法自我总结

目录 1. 编译一个库依赖另一个库 2. 把某一个CMakeLists.txt中变量设为整个工程中任意CMakeLists.txt都可以访问 3. 枚举目录下所有匹配文件 4. 拷贝文件 5. 解决方案下分Header Files,Source Files目录 6. 依赖头文件(附加依赖项) 7.…

通过阿里云函数计算解决ChatGPT API的调用问题

ChatGPT系列文章 与其被ChatGPT取代,不如征服ChatGPT,做它的主人! 文章目录ChatGPT系列文章前言命令行部署准备工作两行命令实现部署应用中心部署使用代理访问API总结前言 自2022年11月30日 OpenAI 发布 ChatGPT 以来,虽然时有唱…

算法训练第四十九天 | 121.买卖股票的最佳时机、122.买卖股票的最佳时机II

动态规划part10121.买卖股票的最佳时机题目描述思路暴力贪心动态规划122.买卖股票的最佳时机II题目描述思路121.买卖股票的最佳时机 题目链接:121.买卖股票的最佳时机 参考:https://programmercarl.com/0121.%E4%B9%B0%E5%8D%96%E8%82%A1%E7%A5%A8%E7%9…

entos7系统部署网站项目教程【超详细教程】

CentOS 7 系统部署项目教程 本文将介绍如何在 CentOS 7 系统上部署项目。在本教程中,我们将使用 Apache、PHP 和 MySQL 作为我们的主要开发工具。对于初学者来说,这是一个入门级的教程,旨在提供一些基本的概念和工具,以帮助您更好…

实践分享:如何在自己的App 中引入AI 画图

最近AIGC 简直是杀疯了,领导动不动就让我们在APP 里引入大语言模型,引入AI画图……说搞就搞!本期基于最近在app 里引入AI画图小程序的操作,给大家做一波实践分享。 Scribble Diffusion 是一个简单的在线服务,它使用 A…

Kotlin 面向对象(二)

【文字内容源于《疯狂Kotlin讲义》,代码内容原创】 Kotlin 面向对象(一)_桃子不出的博客-CSDN博客 目录 四、隐藏和封装 1、包和导包 2、Kotlin的默认导入 3、使用访问控制符 五、深入构造器 1、主构造器和初始化块 2、次构造器和构…

Redis —缓存常见异常

文章目录缓存雪崩解决办法缓存击穿解决办法缓存穿透缓存穿透的两种常见情况解决办法布隆过滤器工作原理缓存雪崩 大量缓存数据在同一时间过期(失效)或者 Redis 故障宕机时,如果此时有大量的用户请求,都无法在 Redis 中处理&#…

父子组件传值问题

文章目录前言一、问题描述二、问题解决前言 在写毕业设计,涉及了一些前端Vue.js的组件传值知识并出现了相关问题,因此进行记录。 问题 Vue.js的使用不熟练,相关组件、props等掌握不清晰前端代码书写不规范 望指正! 一、问题描述 …

php企业公司员工考勤加班系统

1、系统管理员 负责员工的基本信息管理(包括姓名、工号、所在部门信息的添加、修改和删除)和员工的上下班时间的添加。 公司考勤记录方式为刷上下班卡,卡机自动记录员工上下班时间。我直接跳过这一步,系统管理员每天在员工下班后直…

面试被问到:测试计划和测试方案有什么区别?

面试的时候,很多小伙伴都被面试官问过这个问题 “测试计划和测试方案有什么区别”? 到底有什么区别呢?我们先好好了解下这两个文档。 一、测试计划 1、测试计划是什么? 测试计划是组织管理层面的文件,从组织管理的…

派盘为您的个人数据安家

现如今,我们的生活中有着各种各样的数据。在工作中会有各种文件、邮件;在生活中则有照片和视频等。数据的来源多,时间点不一致且混乱。 数据是否能安全、稳定、长久的存储以及便捷高效的使用对我们来说相当重要。你是否经常出差需要带上电脑或者移动硬盘,想存网盘又怕丢失或…

一篇文章,弄懂蓝牙协议怎么看,进军物联网!

做过物联网相关项目的小伙伴都知道,避免不了和蓝牙,串口通信打交道。所以了解怎么看蓝牙协议基本上可以说是进军物联网的一大助力。很多新人小伙伴刚进入这个行业都是一脸懵逼的,特别是接入的时候,对方直接给了一个文档&#xff0…

【WCH】基于Keil环境CH32F203 GPIO点灯实验

【WCH】基于Keil环境CH32F203 GPIO点灯实验📌相关篇《关于CH32F203程序下载方式说明》 ✨如果是首次入门使用,请先看上面的相关篇内容,了解其下载相关事宜后,再进来学习。 GPIO模式介绍 🌿在应用手册的第十章介绍GPIO…
最新文章