【Java设计模式】八、装饰者模式

文章目录

  • 0、背景
  • 1、装饰者模式
  • 2、案例
  • 3、使用场景
  • 4、源码中的实际应用

0、背景

有个快餐店,里面的快餐有炒饭FriedRice 和 炒面FriedNoodles,且加配菜后总价不一样,计算麻烦。如果单独使用继承,那就是:

在这里插入图片描述

类爆炸不说,再来个炒河粉,就发现这样写扩展性很差。

1、装饰者模式

指在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)的模式。角色:

  • 抽象构件:具体构件的规范接口
  • 具体构件:被装饰(被增加功能)的原始对象
  • 抽象装饰:继承抽象构件
  • 具体装饰:实现抽象装饰,给具体构件对象添加功能

总之,用于动态扩展一个类的功能(增强目标对象),而非使用继承

2、案例

在这里插入图片描述

定义快餐类(抽象构件):

//快餐接口
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public abstract class FastFood {
    private float price;
    private String desc;

    public abstract float cost();  //获取价格
}

定义炒饭、炒面类(具体的构件)

//炒饭
public class FriedRice extends FastFood {

    public FriedRice() {
        super(10, "炒饭");    //调用父类的构造方法,给炒饭的价格和描述赋值,即一碗炒饭10元
    }

    public float cost() {
        return getPrice();
    }
}

//炒面
public class FriedNoodles extends FastFood {

    public FriedNoodles() {
        super(12, "炒面");   //调用父类的构造方法,给炒面的价格和描述赋值
    }

    public float cost() {
        return getPrice();
    }
}

定义装饰类,属于抽象装饰角色,实现或者继承抽象构件,并聚合它

//配料
public abstract class Garnish extends FastFood {

    private FastFood fastFood;   //声明抽象构件的变量

    public FastFood getFastFood() {
        return fastFood;
    }

    public void setFastFood(FastFood fastFood) {
        this.fastFood = fastFood;
    }

    public Garnish(FastFood fastFood, float price, String desc) {
        super(price,desc);
        this.fastFood = fastFood;
    }
}

定义配料类(属于具体的装饰者角色),继承装饰者类:

//鸡蛋配料
public class Egg extends Garnish {

    public Egg(FastFood fastFood) {     //给属性赋值
        super(fastFood,1,"鸡蛋");    //一个鸡蛋一块钱 + 一份快餐
    }

    @Override
    public float cost() {
        return getPrice() + getFastFood().getPrice();   //鸡蛋的价格 + 快餐的价格
    }

    @Override
    public String getDesc() {
        return super.getDesc() + getFastFood().getDesc();
    }
}


//培根配料
public class Bacon extends Garnish {

    public Bacon(FastFood fastFood) {

        super(fastFood,2,"培根");   //一个培根两块钱 + 一份快餐
    }

    @Override
    public float cost() {
        return getPrice() + getFastFood().getPrice();
    }

    @Override
    public String getDesc() {
        return super.getDesc() + getFastFood().getDesc();
    }
}

测试:

//测试类
public class Client {
    public static void main(String[] args) {
        //点一份炒饭
        FastFood food = new FriedRice();
        //花费的价格
        System.out.println(food.getDesc() + " " + food.cost() + "元");

        System.out.println("========");
        //点一份加鸡蛋的炒饭
        FastFood food1 = new FriedRice();

        food1 = new Egg(food1);   妙!
        //花费的价格
        System.out.println(food1.getDesc() + " " + food1.cost() + "元");

        System.out.println("========");
        //点一份加培根的炒面
        FastFood food2 = new FriedNoodles();
        food2 = new Bacon(food2); 妙!
        //花费的价格
        System.out.println(food2.getDesc() + " " + food2.cost() + "元");
    }
}

后续如果需求变动,要加一个新配料:火腿,那就定义一个类去继承Garnish类即可。且任何配料可以自由搭配任何主食(组合不同的装饰者对象),这比排列组合写出n个子类好多了。继承是静态的附加责任,装饰者则是动态的附加责任。

3、使用场景

不能采用继承的方式对已有功能进行扩充时,可用装饰者模式。比如:

  • 类被final修饰,不能被继承
  • 扩展项目太多,用继承会子类爆炸
  • 某些功能需要支持动态添加和动态撤销

4、源码中的实际应用

JDK中BufferedWriter等包装类,用到了装饰者模式,对Writer类进行了增强

public class Demo {
    public static void main(String[] args) throws Exception{
        //创建BufferedWriter对象
        //创建FileWriter对象
        FileWriter fw = new FileWriter("C:\\Users\\Think\\Desktop\\a.txt");
        BufferedWriter bw = new BufferedWriter(fw);

        //写数据
        bw.write("hello Buffered");

        bw.close();
    }
}

在这里插入图片描述

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

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

相关文章

Django项目的部署——之环境的重建

Django项目的部署 版本对应 Django 2.0.6 可以匹配mysql5.6.48版本,和mysql5.7.7版本一块用会报错。 其它版本未测试。 创建新的虚拟环境 根据项目版本安装对应的Python包。比如项目开发时用的是python-3.6.4,则安装该版本,并配置环境变量…

【智能家居】东胜物联ODM定制ZigBee网关,助力能源管理解决方案商,提升市场占有率

背景 本文案例服务的客户是专业从事智能家居能源管理的解决方案商,其产品与服务旨在帮助用户监测、管理和优化能源消耗,以提高能源使用效率。 随着公司的扩张,为了增加市场占有率,他们希望找到更好的硬件服务支持,以…

leetcode 3.6

Leetcode hot 100 一.矩阵1.旋转图像 二.链表1. 相交链表2.反转链表3.回文链表4.环形链表5.环形链表 II 一.矩阵 1.旋转图像 旋转图像 观察规律可得: matrix[i][j] 最终会被交换到 matrix [j][n−i−1]位置,最初思路是直接上三角交换,但是会…

学习clickhouse 集群搭建和分布式存储

为什么要用集群 使用集群的主要原因是为了提高系统的可扩展性、可用性和容错性。 可扩展性:当单个节点无法处理增加的负载时,可以通过添加更多的节点到集群来增加处理能力。这使得系统可以处理更大的数据量和更高的查询负载。可用性:在集群…

Java项目:41 springboot大学生入学审核系统的设计与实现010

作者主页:源码空间codegym 简介:Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 项目介绍 本大学生入学审核系统管理员和学生。 管理员功能有个人中心,学生管理,学籍信息管理,入学办理管理等。 学…

解决 RuntimeError: “LayerNormKernelImpl“ not implemented for ‘Half‘

解决 RuntimeError: “LayerNormKernelImpl” not implemented for ‘Half’。 错误类似如下: Traceback (most recent call last): File “cli_demo.py”, line 21, in for results in webglm.stream_query(question): File “/root/WebGLM/model/modeling_webgl…

CTP-API开发系列之三:柜台系统简介

CTP-API开发系列之三:柜台系统简介 CTP-API开发系列之三:柜台系统简介中国金融市场结构---交易所柜台系统通用柜台系统极速柜台系统主席与次席 CTP柜台系统CTP组件名称对照表CTP柜台系统程序包CTP柜台系统架构图 CTP-API开发系列之三:柜台系统…

基于Yolo5模型的动态口罩佩戴识别安卓Android程序设计

禁止完全抄袭,引用注明出处。 下载地址 前排提醒:文件还没过CSDN审核,GitHub也没上传完毕,目前只有模型的.pt文件可以下载。我会尽快更新。 所使用.ptl文件 基于Yolo5的动态口罩佩戴识别模型的pt文件资源-CSDN文库 项目完整文…

信息抽取技术:电商领域的智能化革命与市场策略优化

一、引言 在当今快速发展的互联网电商领域,信息抽取技术的应用已经成为商家优化供应链、降低成本、提高响应速度的关键手段。随着消费者需求的日益多样化和个性化,电子商务平台需要更高效、智能的数据处理能力来应对市场的挑战。从供应商管理到库存优化…

蓝桥杯(3.7)

P1102 A-B 数对 import java.util.Scanner; public class Main {public static void main(String[] args) {Scanner sc new Scanner(System.in);int n sc.nextInt();int c sc.nextInt();int[] res new int[n1];for(int i1;i<n;i)res[i] sc.nextInt();int sum 0;for(i…

看一看阿里云,如何把抽象云概念,用可视化表达出来。

云数据库RDS_关系型数据库 云数据库RDS_关系型数据库 专有宿主机 云数据库RDS_关系型数据库_MySQL源码优化版 内容协作平台CCP-企业网盘协同办公-文件实时共享

python基础——入门必备知识

&#x1f4dd;前言&#xff1a; 本文为专栏python入门基础的第一篇&#xff0c;主要带大家先初步学习一下python中的一些基本知识&#xff0c;认识&#xff0c;了解一下python中的一些专有名词&#xff0c;为日后的学习打下良好的基础,。本文主要讲解以下的python中的基本语法&…

【nodejs】“__dirname is not defined”错误修复

▒ 目录 ▒ &#x1f6eb; 问题描述环境 1️⃣ 原理CommonJS vs ESM错误原因 2️⃣ 禁用 ESM 模式并改用 CommonJS方案一&#xff1a;项目方案二&#xff1a;单文件 3️⃣ 在 ESM 模式下自实现__dirname&#x1f4d6; 参考资料 &#x1f6eb; 问题 描述 从网上找了一份代码&am…

opengl 学习(一)-----创建窗口

创建窗口 分类opengl 学习(一)-----创建窗口效果解析教程补充 分类 c opengl opengl 学习(一)-----创建窗口 demo: #include "glad/glad.h" #include "glfw3.h" #include <iostream> #include <cmath> #include <vector>using names…

智能控制:物联网智能插座对接文档

介绍 一开始买的某米的插座&#xff0c;但是好像接口不开放&#xff0c;所以找到了这个插座&#xff0c;然后自己开发了下&#xff0c;用接口控制插座开关。wifi的连接方式&#xff0c;通电后一般几秒后就会连接上wifi&#xff0c;这个时候通过接口发送命令给他。 产品图片 通…

第十篇:复习maven

文章目录 一、什么是Maven1. 依赖管理2. 统一项目结构3. 项目构建4. 依赖的仓库 二、IDEA集成Maven1. Maven简单的安装和配置2. 配置Maven环境3. 创建Maven项目4. Maven坐标4. 导入Maven项目 三、依赖管理1. 依赖配置2. 依赖传递3. 依赖范围4. 生命周期 四、小结 一、什么是Mav…

SAP MM学习笔记 - 错误 BMG140 - The material number is longer than the length set

错误 BMG140 - The material number is longer than the length set 品目编号大于长度设置 1&#xff0c;在新规品目的时候&#xff0c;出的错 2&#xff0c;OMSL 品目Code书式变更 IMG path>Logistic general>Material Master>Basic settings>Define output for…

【Web前端入门学习】—CSS

目录 CSS简介CSS语法CSS三种导入方式CSS选择器元素选择器&#xff08;标签选择器&#xff09;类选择器ID选择器通用选择器子元素选择器后代选择器&#xff08;包含选择器&#xff09;并集选择器&#xff08;兄弟选择器&#xff09;伪类选择器伪元素选择器 CSS常用属性盒子模型网…

TabLayout预览不了?

<TableLayoutandroid:layout_width"wrap_content"android:layout_height"wrap_content"/> 当然预览不了了&#xff0c;这其实不是我要的控件。 而实际需要的是TabLayout 不是TableLayout &#xff01;&#xff01;&#xff01; <com.google.an…

机器学习——感知机模型

机器学习系列文章 入门必读&#xff1a;机器学习介绍 文章目录 机器学习系列文章前言1. 感知机1.1 感知机定义1.2 感知机学习策略 2. 代码实现2.1 构建数据2.2 编写函数2.3 迭代 3. 总结 前言 大家好&#xff0c;大家好✨&#xff0c;这里是bio&#x1f996;。这次为大家带来…