大话设计模式-装饰器模式

大话设计模式书中,作者举了一个穿衣服的例子来为我们引入装饰器模式。


概念


定义

装饰模式在书中的定义是:
动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更灵活。

这句话直接去理解可能会有点抽象,我结合书中的例子来讲讲自己的理解。假设有一天,女朋友要你陪她去逛商场,她今天要做很多事情:

  • 去干洗店拿干洗的衣服
  • 去服装店取定制地衣服
  • 去做头发
  • 去美甲
  • 去美食街吃夜宵
  • ......

她去做这些事情地顺序是不确定的,而且这些事情之间也没有什么太大的关联。那我们在程序中去把这些事情串联起来呢?简单的为每一种操作写一个类,然后在主函数中排列组合吗?这样做也不是不可以,但是这就破坏了我们程序当中的封装性。用书中的话说就是:

你光着身子, 当着大家的面,先穿T恤,再穿裤子,再穿鞋,仿佛在跳穿衣舞。难道你穿衣服都是在众目睽睽下穿的吗?

实际上,大多数时候我们不希望将太多的细节暴露给用户,因此面对这种情况,我们可能就需要用到装饰模式。让我们先来看看它的结构图。

结构

这是作者在书中给出的原图。同样,直接看图可能很难让我们理解什么是策略模式。我们继续用上面那个例子来类比举例。

Component是定义一个对象接口,可以给这些对象动态地添加职责。

这句话怎么理解,其实在上面这个例子中,Conponent其实就相当于“人”。为什么这么说,因为只有“人”才能完成拿衣服,买衣服,做头发等等这些事情(不要抬杠哈,你懂我意思)。那这个Operation()方法就相当于是做完了的事情(可以是空的或者多件事情的排列组合)。

ConcreteComponent是定义了一个具体的对象,也可以给这个 对象添加一些职责。

这句话又怎么理解呢,你可以把ConcreteComponent看成是女朋友,她是一个具体的人,是她要去完成这些行为。同样Operation()方法就相当于是她已经做完了的事情(可以是空的或者多件事情的排列组合)。

Decorator,装饰抽象类,继承了Component, 从外类来扩展Component类的功能,但对于Component来说,是无需知道Decorator的存在的。至于ConcreteDecorator就是具体的装饰 对象,起到给Component添加职责的功能。

这句话比较长,也比较抽象。什么是装饰抽象类,在这个例子中还真不是很好解释,你可以理解为一个“盒子”,里面装的是“前一刻的女朋友”(可能比较牵强哈)。或者更好的理解是把他当成一种规则:你这个人在进我们店之前是什么样的,带了哪些东西;你带来的东西我们原封不动,我们店给你提供了一些服务之后,你还是完完整整的一个人从我这里走出去。所有的店都必须遵循这个规则(不然就是黑店了)。ConcreteDecorator就相当于是遵循这些规则的具体的干洗店,服装店,理发店,美甲店,小吃店等等了。

那么整个流程是怎么样的呢。

  1. 女朋友出门饿了,先来小吃店吃了小吃,变成了“吃了小吃的女朋友”
  2. “吃了小吃的女朋友”吃太饱了,准备去干洗店先拿一下衣服,变成了“拿了衣服的吃了小吃的女朋友”
  3. “拿了衣服的吃了小吃的女朋友”觉得走累了,先去理发店做个于是头发休息一下,变成了“做了头发的拿了衣服的吃了小吃的女朋友”
  4. ......
  5. 最后女朋友做完了所有的事情

经过这个流程,大家应该能够理解了具体装饰类的作用了吧。比如装饰类A的作用就是,把B的C变成A的B的C

优缺点

优点:

在书中对于装饰模式的优点是这样说的:

装饰模式是利用SetComponent来对对象进行包 装的。这样每个装饰对象的实现就和如何使用这个对象分离开了, 每个装饰对象只关心自己的功能,不需要关心如何被添加到对象链当中。

其实我觉得它的主要优点还是增强了扩展对象功能的灵活性。并且减少了细节的暴露。

缺点:

主要的缺点就是:可能会增加程序的复杂性,因为它的结构相较于直接在主程序中“跳穿衣舞”更加难以理解,因为它需要将对象一层一层的包裹起来,如果过度使用的话可能会让程序变得复杂。

例子


我们尝试用Java实现一下上面的例子。并对其中的一些细节进行相应的优化。

  1. 由于整个事情中,出现的人只有女朋友一个,因此可以将人这个父类省略。女朋友类的代码如下:
    /**
     * @Author yirui
     * @Date 2024/4/17 20:58
     * @Version 1.0
     */
    public class GirlFriend {
        public void Operation(){
            System.out.println("女朋友");
        }
    }
    

  2. 由于没有人这个父类(父子类的概念参考简单工厂模式中所介绍的),那修饰抽象类只能继承女朋友类了,规则变成:女朋友在进店之前是什么样的,带了哪些东西;带来的东西我们原封不动,我们店给女朋友提供了一些服务之后,女朋友还是完完整整的一个人从我这里走出去。(其实这个例子中,这个类都可以不要,直接让具体修饰类继承女朋友类就可以了,但是为了方便理解,还是把它写出来了):

    /**
     * @Author yirui
     * @Date 2024/4/17 21:03
     * @Version 1.0
     */
    public class Decorator extends GirlFriend{
        GirlFriend girlFriend;
    
        public void setGirlFriend(GirlFriend girlFriend) {
            this.girlFriend = girlFriend;
        }
    
        @Override
        public void Operation() {
            girlFriend.Operation();
        }
    }
    
  3. 接下来就是具体修饰类了,继承修饰抽象类。(这里为了省事,只写干洗店和小吃店。)
     

    /**
     * @Author yirui
     * @Date 2024/4/17 21:08
     * @Version 1.0
     */
    public class ClothingStore extends Decorator{
        private void buyCloth(){
            System.out.println("买了一件衣服。");
        }
    
        @Override
        public void Operation() {
            super.Operation();
            buyCloth();
        }
    }
    
    
    /**
     * @Author yirui
     * @Date 2024/4/17 21:11
     * @Version 1.0
     */
    public class FoodStore extends Decorator{
        private void eatFood(){
            System.out.println("吃了一碗麻辣烫。");
        }
    
        @Override
        public void Operation() {
            super.Operation();
            eatFood();
        }
    }
    
  4. 主程序:
     

    /**
     * @Author yirui
     * @Date 2024/4/17 21:13
     * @Version 1.0
     */
    public class Program {
        public static void main(String[] args) {
            GirlFriend girlFriend = new GirlFriend();
            ClothingStore clothingStore = new ClothingStore();
            FoodStore foodStore = new FoodStore();
    
            clothingStore.setGirlFriend(girlFriend);
            clothingStore.Operation();
            System.out.println("**********************");
            foodStore.setGirlFriend(clothingStore);
            foodStore.Operation();
        }
    }
    
  5. 结果如图,可以看到,女朋友先去了服装店,变成了女朋友买了一件衣服。这个时候,买了一件衣服的女朋友又去了小吃店,最终变成了,女朋友买了一件衣服,吃了一碗麻辣烫。

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

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

相关文章

javase__进阶 day13stream流和方法引用

1.不可变集合 1.1 什么是不可变集合 ​ 是一个长度不可变,内容也无法修改的集合 1.2 使用场景 ​ 如果某个数据不能被修改,把它防御性地拷贝到不可变集合中是个很好的实践。 ​ 当集合对象被不可信的库调用时,不可变形式是安全的。 简单…

java:Java中的抽象类

什么是抽象类: 我们知道,类用来模拟现实的事物,一个类模拟一类事物,某个类的一个实例化对象可以模拟某个属于该类的具体事物。类中描绘了该类所有对象的共同的特性,当一个类中给出的信息足够全面时候,我们就…

如何从零开始创建React应用:简易指南

🌟 前言 欢迎来到我的技术小宇宙!🌌 这里不仅是我记录技术点滴的后花园,也是我分享学习心得和项目经验的乐园。📚 无论你是技术小白还是资深大牛,这里总有一些内容能触动你的好奇心。🔍 &#x…

【大模型应用极简开发入门(1)】LLM概述:LLM在AI中所处位置、NLP技术的演变、Transformer与GPT、以及GPT模型文本生成逻辑

文章目录 一. AI中大语言模型的位置与技术发展1. 从AI到Transformer2. NLP:自然语言处理3. LLM大型语言模型:NLP的一种特定技术3.1. LLM定义3.2. LLM的技术发展3.2.1. n-gram模型3.2.2. RNN与LSTM 二. Transformer在LLM中脱颖而出1. Transformer架构能力…

【Linux】详解进程通信中信号量的本质同步和互斥的概念临界资源和临界区的概念

一、同步和互斥的概念 1.1、同步 访问资源在安全的前提下,具有一定的顺序性,就叫做同步。在多道程序系统中,由于资源有限,进程或线程之间可能产生冲突。同步机制就是为了解决这些冲突,保证进程或线程之间能够按照既定…

sketchup创建3D打印机的模型

查了一下,这玩意有几个版本,其中一个sketchup free是免费的,到官网上看看 下载 SketchUp | 免费试用 3D 建模软件 | SketchUp 是个在线网页版,然后可以再这个网站上注册一个账号 弄个邮箱试试看 创建好进入后,里面就…

解锁多智能体路径规划新境界:结合启发式搜索提升ML本地策略

引言:多智能体路径寻找(MAPF)问题的重要性与挑战 在现代自动化和机器人技术迅速发展的背景下,多智能体路径寻找(Multi-agent path finding,简称MAPF)问题的研究变得日益重要。MAPF问题涉及为一…

《QT实用小工具·二十七》各种炫酷的样式表

1、概述 源码放在文章末尾 该项目实现了各种炫酷的样式表,如单选、多选、按钮、日历、表格、下拉框、滚轮等,下面是项目demo演示: 项目部分代码如下: #include "frmmain.h" #include "ui_frmmain.h" #inc…

【C++】飞机大战项目记录

源代码与图片参考自《你好编程》的飞机大战项目,这里不进行展示。 本项目是仅供学习使用的项目 飞机大战项目记录 飞机大战设计报告1 项目框架分析1.1 敌机设计:1.2 玩家飞机控制:1.3 子弹发射:1.4 游戏界面与互动:1.5…

高精度算法(2)

前言 延续上次所讲的内容再对乘法和除法进行说明,希望有所帮助 注意这里的乘除法都是针对于整数如果要是涉及到小数,我们得使用二分法 通过二分同样可以解决小数精度问题 高精度乘法 思路 我们只能用字符串来读取一个很大很大的数,所以…

一文讲透彻Redis 持久化

文章目录 ⛄1.RDB持久化🪂🪂1.1.执行时机🪂🪂1.2.RDB原理🪂🪂1.3.小结 ⛄2.AOF持久化🪂🪂2.1.AOF原理🪂🪂2.2.AOF配置🪂🪂2.3.AOF文件…

按钮(秒懂CSS按钮的使用)

目录 一、按钮介绍 1.概念 2.特点 3.功能 二、按钮用法 1.按钮的使用 2.按钮的样式 3.按钮颜色 4.按钮大小 5.圆角按钮 6.按钮边框颜色 7.按钮鼠标悬停 8.按钮阴影 9.禁用按钮 10.按钮宽度 三、按钮实例 1.交互式按钮 2.扩展动画按钮 3.播放/暂停按钮 四、应用场景…

国产化里程碑:明道云HAP私有部署版获信创评估证书,荣登会员单位

近期,明道云HAP私有部署版荣获信创产品评估证书,这一成就不仅标志着我们在信创领域的深入布局和持续努力获得了行业的广泛认可,也是对我们积极拥抱和推动国产化技术发展的肯定。更值得一提的是,我们还被授予“成员单位”的称号&am…

【数字电路与系统】【北京航空航天大学】实验:时序逻辑设计——三色灯开关(二)、需求分析和系统设计

本次实验(一)见博客:【数字电路与系统】【北京航空航天大学】实验:时序逻辑设计——三色灯开关(一)、实验指导书 说明:本次实验的代码使用verilog编写,文章中为阅读方便&#xff0c…

kaggle 房价预测 得分0.53492

流程 导入需要的包引入文件,查看内容数据处理调用模型准备训练输出结果 导入需要的包 import pandas as pd import numpy as np import matplotlib.pyplot as plt import seaborn as sns from sklearn.model_selection import train_test_split from sklearn.linear_model i…

Claude 3 Opus 效果是否真的可以超过GPT-4?

实测,不仅是超过,而且我个人感觉这个差距甚至大于GPT3.5到GPT4的距离. claude3在长篇理学论文的解析能力是非常显著的,可以扩展补完作者省略的大量运用高等数学,复变函数以及更多数理方法的计算过程,并且将中间过程补完的非常完美.不会漏符号,错符号,偏差数值之类的问题.工科许…

【C语言】贪吃蛇项目(2)- 实现代码详解

文章目录 前言一、游戏开始界面设计首先 - 打印环境界面其次 - 游戏地图、蛇身及食物的设计1、地图2、蛇身设置及打印3、食物 二、游戏运行环节蛇的上下左右移动等功能蛇的移动 三、结束游戏代码 前言 在笔者的前一篇博客中详细记载了贪吃蛇项目所需的一些必备知识以及我们进行…

mysql_explain执行计划字段解析

【README】 本文对 explain打印的执行结果的字段进行解析; 本文总结自: MySQL :: MySQL 8.3 Reference Manual :: 10.8.2 EXPLAIN Output Formathttps://dev.mysql.com/doc/refman/8.3/en/explain-output.html 列名含义id选择标识select_type选择类型…

移动Web学习09-响应式布局bootstrap案例开发

3、综合案例-AlloyTeam移动全端 准备工作 HTML 结构 <title>腾讯全端</title> <link rel"shortcut icon" href"favicon.ico" type"image/x-icon"> <!-- 层叠性&#xff1a;咱们的css 要 层叠 框架的 --> <link rel&…

存储过程的使用(二)

目录 带 OUT 参数的存储过程 输入一个编号&#xff0c;查询数据表 emp中是否有这个编号&#xff0c;如果有返回对应员工姓名&#xff0c;如果没有&#xff0c;则提示没有对应员工 使用 EXEC 命令或者 PRINT执行含有 OUT参数的存储过程 使用 PL/SQL 块编辑程序调用含有 OUT …