装饰器模式-原理分析以及动手练习

news2024/11/26 2:50:21

目录

    • 应用场景
    • 涉及的角色和类(个人理解)
    • 涉及的角色组件(标准)
    • 基本实现 Demo(可以直接 copy 跑一下看效果)
    • 自己动手实战
      • 需求
      • 参考答案
    • 相关话题
    • 参考文章

应用场景

  • 需要给一个现有类添加附加功能,但由于某些原因不能使用继承来生成子类进行扩充时,可以使用装饰模式。
  • 当对象的功能要求可以动态地添加,也可以再动态地撤销时,可以使用装饰模式。

涉及的角色和类(个人理解)

  • 简单来说是两类角色:Source(Component)Decorator,即 被装饰者(原类)装饰者
  • 从类实现分析:
    • 由于 被装饰者装饰者 需要实现同样的方法,需要定义一个抽象接口。
    • 为便于区分,被装饰者抽象接口叫 Component,具体的被装饰者叫 ConcreteComponent
    • 考虑到可能有多个具体的装饰器,需要一个抽象类装饰器叫 Decorator,它的多个具体实现类分别叫 AConcreteDecorator, BConcreteDecorator
      在这里插入图片描述

涉及的角色组件(标准)

  • 被装饰组件接口:Component
  • 具体的被装饰组件实现类:AConcreteComponent, BConcreteComponent
  • 装饰器抽象类:Decorator
  • 具体的被装饰器实现类:AConcreteDecorator, BConcreteDecorator

基本实现 Demo(可以直接 copy 跑一下看效果)

  • Demo,有一个 图形Shape 被装饰接口,有 两个被装饰者的具体实现 Circle, Rectangle,有两个装饰器,分别用来 给图形设置绿色给图形设置红色
  • 在本地创建一个java类 DecoratorTest02,然后 copy 一下代码,直接跑
/**
 * 装饰器模式要实现的类
 * Component
 * AConcreteComponent
 * BConcreteComponent
 * Decorator
 * AConcreteDecorator
 * BConcreteDecorator
 */

// 1. 实现 被装饰器组件 操作
// Component
interface Shape {
    void draw();
}

// 2. 实现 被装饰器组件 的具体实现类
// AConcreteComponent
class Circle implements Shape {
    @Override
    public void draw() {
        System.out.println("画一个圆形");
    }
}

// BConcreteComponent
class Rectangle implements Shape {
    @Override
    public void draw() {
        System.out.println("画一个方形");
    }
}

// 3. 实现 装饰器
// Decorator
abstract class Decorator implements Shape {
    // 使用 protected,便于子类访问
    protected Shape shape;

    public Decorator(Shape shape) {
        this.shape = shape;
    }

    @Override
    public void draw() {
        shape.draw();
    }

}

// 4. 实现 具体功能的 装饰器
// AConcreteDecorator
class RedDecorator extends Decorator {

    public RedDecorator(Shape shape) {
        super(shape);
    }

    @Override
    public void draw() {
        // 可以在原功能之前增加功能
        // 调用原方法
        shape.draw();
        // 可以在原功能之后增加功能
        setRed(shape);
    }

    // 装饰器功能:设置红色
    public void setRed(Shape shape) {
        System.out.println("设置红色");
    }
}

// BConcreteDecorator
class GreenDecorator extends Decorator {

    public GreenDecorator(Shape shape) {
        super(shape);
    }

    @Override
    public void draw() {
        shape.draw();
        setRed(shape);
    }

    // 装饰器功能:设置绿色
    public void setRed(Shape shape) {
        System.out.println("设置绿色");
    }
}

// 5. 在客户端中使用 装饰器
public class DecoratorTest02 {
    public static void main(String[] args) {
        // 1. 标准的使用过程,画一个 圆,红色的
        // 创建一个 被装饰器组件圆
        Circle circle = new Circle();
        // 创建一个 具体的装饰器红色
        RedDecorator redDecorator = new RedDecorator(circle);
        // 执行方法
        redDecorator.draw();

        // 2. 画一个 方形,红色的
        new RedDecorator(new Rectangle()).draw();

        // 3. 画一个 方形,绿色的
        new GreenDecorator(new Rectangle()).draw();

        // 4. 画一个 方形,红绿色的(可以组合多个装饰功能)
        new RedDecorator(new GreenDecorator(new Rectangle())).draw();

        // 总结 可以看出,使用装饰器,可以对原来的类 动态添加、删除装饰功能
    }
}

自己动手实战

需求

小明喜欢品尝不同口味的咖啡,他发现每种咖啡都可以加入不同的调料,比如牛奶、糖和巧克力。他决定使用装饰者模式制作自己喜欢的咖啡。

请设计一个简单的咖啡制作系统,使用装饰者模式为咖啡添加不同的调料。系统支持两种咖啡类型:黑咖啡(Black Coffee)和拿铁(Latte)。

要求:可以制作 加牛奶的黑咖啡,加糖的黑咖啡,加糖的拿铁咖啡

原练习题链接

参考答案

// Component: 被装饰者接口
interface Coffee {
    void createCoffee();
}

// AConcreteComponent: 被装饰者的具体实现类 黑咖啡
class BlackCoffee implements Coffee {
    @Override
    public void createCoffee() {
        System.out.println("create black coffee");
    }
}

// BConcreteComponent: 被装饰者的具体实现类 拿铁咖啡
class Latte implements Coffee {
    @Override
    public void createCoffee() {
        System.out.println("create latte coffee");
    }
}


// Decorator: 装饰器抽象类
abstract class Decorator implements Coffee {
    // 让子类可以访问到 被装饰者
    protected Coffee coffee;

    public Decorator(Coffee coffee) {
        this.coffee = coffee;
    }

    @Override
    public void createCoffee() {
        coffee.createCoffee();
    }
}

// AConcreteDecorator: 装饰器具体实现类 加牛奶装饰
class MilkDecorator extends Decorator {
    public MilkDecorator(Coffee coffee) {
        super(coffee);
    }

    @Override
    public void createCoffee() {
        // 在原方法之前 做装饰
        washCup();
        // 执行原方法
        coffee.createCoffee();
        // 在原方法之后做装饰
        addMilk(coffee);
    }

    // 装饰功能:洗杯子
    public void washCup() {
        System.out.println("洗杯子");
    }

    // 装饰功能:加牛奶
    public void addMilk(Coffee coffee) {
        System.out.println("加入牛奶");
    }
}

// BConcreteDecorator: 装饰器具体实现类 加糖装饰
class SugarDecorator extends Decorator {
    public SugarDecorator(Coffee coffee) {
        super(coffee);
    }

    @Override
    public void createCoffee() {
        coffee.createCoffee();
        addSugar(coffee);
    }

    public void addSugar(Coffee coffee) {
        System.out.println("加入一些糖");
    }
}

public class DecoratorTest01 {
    public static void main(String[] args) {
        BlackCoffee blackCoffee = new BlackCoffee();
        SugarDecorator sugarDecorator = new SugarDecorator(blackCoffee);
        sugarDecorator.createCoffee();
    }
}

相关话题

  • Java IO 流中如何应用的装饰器模式
  • 什么时候可以考虑使用装饰器模式
  • 能徒手写一个装饰器模式的demo吗

参考文章

  • https://github.com/youngyangyang04/kama-DesignPattern/blob/main/DesignPattern/8-%E8%A3%85%E9%A5%B0%E6%A8%A1%E5%BC%8F.md
  • https://www.runoob.com/design-pattern/decorator-pattern.html
  • https://pdai.tech/md/java/io/java-io-basic-design-pattern.html
  • https://kamacoder.com/problempage.php?pid=1086

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何安全可控地进行内外网跨网络传输文件?

跨网络传输文件通常指的是在不同的网络环境之间移动数据,这在现代企业运营中非常常见。随着网络技术的高速发展,为了有效地保护内部的核心数据资产,企业一般会采用内外网隔离的策略。在进行内外网跨网络传输文件时,需要考虑多种因…

Java性能优化(一):Java基础-ArrayList和LinkedList

引言 集合作为一种存储数据的容器,是我们日常开发中使用最频繁的对象类型之一。JDK为开发者提供了一系列的集合类型,这些集合类型使用不同的数据结构来实现。因此,不同的集合类型,使用场景也不同。 很多同学在面试的时候&#x…

2024爆火的AI设备Rabbit R1到底是什么?有人说它是AI的iPhone时刻,有人说它是套壳的安卓

大家好,我是木易,一个持续关注AI领域的互联网技术产品经理,国内Top2本科,美国Top10 CS研究生,MBA。我坚信AI是普通人变强的“外挂”,所以创建了“AI信息Gap”这个公众号,专注于分享AI全维度知识…

22_Scala集合Seq

文章目录 Seq序列1.构建集合2.List集合元素拼接&&集合拼接3.可变Seq&&List3.1 ListBuffer创建3.2 增删改查3.3 相互转化 Appendix1.Scala起别名2.Seq底层3.关于运算符操作: :4.空集合的表示 Seq序列 –Seq表示有序,数据可重复的集合 1.构建集合 …

IOS离线打包uniapp的信息时报错如下的解决方法

IOS离线打包uniapp的信息时报错如下的解决方法 问题描述: Extract app intents metadata 0.1 seconds XExtractAppIntentsMetadata(in target HBuilder from project HBuilder-Hello)cd /Users/whb/space/vpt/vptios/HBuilder-Hello/Applications/Xcode.app/Conte…

短视频素材有版权吗?8个没版权的短视频素材购买

在数字媒体日益盛行的今天,高效地利用视频素材不仅能够提升视觉效果,还能有效传达信息和吸引观众。以下是一些全球知名的视频素材网站,它们提供从基础到高端的各类素材,帮助您在任何视频项目中实现创意和提升影响力。 1. 蛙学府&…

Ansible——Playbook剧本

目录 一、Playbook概述 1.Playbook定义 2.Playbook组成 3.Playbook配置文件详解 4.运行Playbook 4.1Ansible-Playbook相关命令 4.2运行Playbook启动httpd服务 4.3变量的定义和引用 4.4指定远程主机sudo切换用户 4.5When——条件判断 4.6迭代 4.6.1创建文件夹 4.6.2…

STM32单片机ADC功能详解

文章目录 1. ADC概述 2. ADC结构图 3. 引脚定义 4. 转换模式 5. 数据对齐 6. 转换时间 7. 硬件电路 8. STM32使用ADC单/多通道检测数据 1. ADC概述 功能:ADC是一个将模拟信号(如电压)转换为数字信号的设备。在微控制器中&#xff0c…

有哪些方式可以有效地评估精益生产咨询公司的能力?

在寻求精益生产咨询服务的过程中,评估咨询公司的能力至关重要。这不仅关乎企业精益生产转型的成功与否,更直接影响到企业未来的竞争力和发展。那么,有哪些方式可以有效地评估精益生产咨询公司的能力呢? 首先,了解咨询公…

【一起深度学习-----VGG】

VGG 原理图: 原理图: 为啥要使用VGG块呢? 对于AlexNet网络来说,虽然十分高效了,但是它并没有提供一个通用的模板,方便后续的研究。 故采用了模块化的思想,方便重复使用。 其实对比于AlexNet神经…

爬虫学习(3)豆瓣电影

代码 import requests import jsonif __name__ "__main__":url https://movie.douban.com/j/chart/top_list#post请求参数处理(同get请求一致)headers {"User-Agent": Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/53…

智启算力平台基本操作

智启算力平台 智启算力平台路径搭载数据集搭载镜像配置 智启算力平台 开发文档 帮助文档 - OpenI - 启智AI开源社区 路径搭载 OpenIOSSG/promote: 启智AI协作平台首页推荐组织及推荐项目申请。 - notice/Other_notes/SDKGetPath.md at master - promote - OpenI - 启智AI开…

docker部署elasticsearch7.7.0级拼音(pinyin)插件和分词(ik)插件

拉取并启动es docker run -d --namees -p 9200:9200 -p 9300:9300 -e "discovery.typesingle-node" elasticsearch:7.7.0安装pinyin插件 下载pinyin插件 下载ik插件 上传插件到服务器 docker cp /path/to/elasticsearch-analysis-pinyin-7.7.0.zip elasticsearch…

Python读取ASC文件并转换成Excel文件(坐标)

import pandas as pd# 读取asc文件,指定空格为分隔符 df pd.read_csv(out_view2.asc, sep , headerNone)# 去掉空列 df df.dropna(howall, axis1)# 将数据保存到Excel文件 df.to_excel(out_view2.xlsx, indexFalse, headerFalse)效果图

【busybox记录】【shell指令】cut

目录 内容来源: 【GUN】【cut】指令介绍 【busybox】【cut】指令介绍 【linux】【cut】指令介绍 使用示例: 关于参数的特殊说明: 打印行中选定部分 - 输出每行的第n-m个字节 打印行中选定部分 - 输出每行的第n-m个字符 打印行中选定…

Flume+Hadoop:打造你的大数据处理流水线

引言 在大数据处理中,日志数据的采集是数据分析的第一步。Apache Flume是一个分布式、可靠且可用的系统,用于有效地收集、聚合和移动大量日志数据到集中式数据存储。本文将详细介绍如何使用Flume采集日志数据,并将其上传到Hadoop分布式文件系…

视频剪辑图文实例:一键操作,轻松实现视频批量片头片尾减时

视频剪辑是现代媒体制作中不可或缺的一环,而批量处理视频更是许多专业人士和爱好者的常见需求。在剪辑过程中,调整视频的片头片尾时长可以显著提升视频的质量和观感。本文将通过图文实例的方式,向您展示如何一键操作,轻松实现视频…

面试集中营—Redis面试题

一、Redis的线程模型 Redis是基于非阻塞的IO复用模型,内部使用文件事件处理器(file event handler),这个文件事件处理器是单线程的,所以Redis才叫做单线程的模型,它采用IO多路复用机制同时监听多个socket&a…

Ubuntu24.04安装中文输入法

Ubuntu24.04安装中文输入法 为了更好的体验,请访问个人博客 www.huerpu.cc:7000 一、添加中文语言支持 在安装中文输入法之前,首选要添加中文语言支持。选择System,点击Region & Language。 点击Manage Install Languages。 点击Insta…

Ansible自动化运维工具 - playbook 剧本编写

一. inventory 主机清单 Inventory 支持对主机进行分组,每个组内可以定义多个主机,每个主机都可以定义在任何一个或多个主机组内。 1.1 inventory 中的变量含义 Inventory 变量名 含义ansible_hostansible连接节点时的IP地址ansible_port连接对方…