【结构型模式】装饰器模式

​一、装饰器模式概述

        装饰器模式(装饰者模式)定义装饰器模式动态地将责任附加到对象上。若要拓展功能,装饰者提供了比继承更有弹性地替代方案。(对象结构型模型)通俗点来说:动态的给一个对象增加一些额外的职责。就扩展功能而言,装饰模式提供了一种比使用子类更加灵活的替代方案。

  • 利用继承来达到“类型匹配”
    • 1.装饰者与被装饰对象有相同地超类型;
    • 2.可以用一个或多个装饰者包装一个对象;
    • 3.既然装饰者与被装饰对象有相同地超类型,所以在任何需要原始对象(被包装地)的场合,可以用装饰过的兑现代替它;
    • 4.装饰者可以在所委托被装饰者的行为之前与/之后,加上自己的行为,以达到特定的目的;
    • 5.对象可以在任何时候被装饰,所以可以在运行时动态地、不限量地用你喜欢的装饰者来装饰对象。
  •  装饰模式分析
    • 1.可以在不改变一个对象本身功能的基础上给对象增加额外的新行为;
    • 2.是一种用于替代继承的技术,它通过一种无需有定义子类的方式给对象动态增加职责,使用对象之间的关联关系取代类之间的继承关系;
    • 3.引入了装饰类,在装饰类中既可以调用装饰的原有类的方法,还可以增加新的方法,以扩展原有类的功能。

        ​透明装饰模式与半透明装饰模式

  • 半透明装饰模式
    • 1.可以给系统带来更多的灵活性,设计相对简单,使用起来也方便;
    • 2.客户端使用具体装饰类型来定义装饰后的对象,因此可以单独调用addedBehavior()方法;
    • 3.最大的缺点在于不能实现对同一个对象的多次装饰,而且客户端需要有区别地对待装饰之前的对象和装饰之后的对象;
    • 4.用具体装饰定义装饰之后的对象,而具体构件使用抽象构件类型来定义;
    • 5.对于客户而言,具体构件类型无须关心,是透明的;但是具体装饰类型必须指定,这并不是透明的。
  • 透明装饰模式
    • 1.要求客户端完全针对抽象编程,装饰模式的透明性要求客户端程序不应该将对象声明为具体构件类型或具体装饰类型,而应该全部声明为抽象构件类型;
    • 2.对客户端而言,具体构件对象和具体装饰对象没有任何区别;
    • 3.可以让客户透明地使用装饰之前地对象和装饰之后地对象,无须关心他们的区别;
    • 4.可以对一个已装饰过地对象进行多次装饰,得到更多复杂、功能更为强大的对象;
    • 5.无法在客户端单独调用新增addedBehavior()方法
  • 适用环境
    • 1.在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责;
    • 2.当不能采用继承的方式对系统进行扩展或者采用继承不利于系统扩展和维护时可以使用装饰模式

        装饰者模式优缺点

  • 优点
    • 1.对于扩展一个对象功能,装饰模式比继承更加灵活,不会导致类的个数急剧增加;
    • 2.可以通过一种动态的方式来扩展一个对象的功能,通过配置文件可以在运行时选择不同的具体装饰类,从而实现不同的行为;
    • 3.可以对一个对象进行多次装饰;
    • 4.具体构件类与具体装饰类可以独立变化,用户可以根据需要增加新的具体构件类和具体装饰类,且原有类库代码无需变化,符合开闭原则。
  • 缺点
    • 1.使用装饰模式进行系统设计时将产生很多小对象,大量对象对象的产生势必会占用更多的系统资源,在一定程度上影响程序的性能;
    • 2.比继承更加易于出错,排错也更困难,对于多次装饰的对象,调试时寻找错误可能需要逐级排查,较为繁琐。

二、代码实现

        结构包含四个角色:

  • 抽象构件(Component)
  • 具体构件(ConcreteComponent)
  • 抽象装饰类(Decorator)
  • 具体装饰类(ConcreteDecorator)
         2.1 星巴兹咖啡

        2.1.1 抽象构件(抽象基类饮料Beverage)
package decorator.dec;
//抽象构件:饮料
public abstract class Beverage {String description = "Unknown Noodle";int size;//小杯TALL、中杯GRANDE、大杯WENTIpublic final static int TALL=1;public final static int GRANDE=2;public final static int WENTI=3;public String getDescription() {return description;}public void setDescription(String description) {this.description = description;}public int getSize() {return size;}public void setSize(int size) {this.size = size;}public abstract double cost();
}
        2.1.2 具体构件(基于饮料的咖啡:DarkRoast、Decaf、Espressio、HouseBlend)
package decorator.dec;
//意大利浓咖啡
public class DarkRoast extends Beverage{public DarkRoast() {description = "DarkRoast";}public double cost() {return 3;}
}
package decorator.dec;
//不加咖啡因的咖啡
public class Decaf extends Beverage{public Decaf() {description = "Decaf";}public double cost() {return 2;}
}
package decorator.dec;
//意式浓缩咖啡
public class Espressio extends Beverage{public Espressio() {description = "Espressio";}public double cost() {return 2.5;}
}
package decorator.dec;
//混合咖啡
public class HouseBlend extends Beverage{public HouseBlend() {description = "HouseBlend";}public double cost() {return 1.5;}
}
        2.1.3 抽象装饰类(抽象装饰类CondimentDecorator)
package decorator.dec;
//抽象装饰类:描述->>配料继承父类,附加在父类上
public abstract class CondimentDecorator extends Beverage{Beverage beverage;public abstract String getDescription();
}
        2.1.4 具体装饰类(添加在咖啡上的牛奶milk、抹茶Mocha、豆奶Soy、咖啡的大小Size、搅拌Whip)
package decorator.dec;
//牛奶
public class milk extends CondimentDecorator{public milk(Beverage beverage) {this.beverage=beverage;}public String getDescription() {return beverage.getDescription() + ",Milk";}public double cost() {return 1+beverage.cost();}
}
package decorator.dec;
//抹茶
public class Mocha extends CondimentDecorator {public Mocha(Beverage beverage) {this.beverage=beverage;}@Overridepublic String getDescription() {// TODO 自动生成的方法存根return beverage.getDescription() + ",Mocha";}public double cost() {return 1+beverage.cost();}}
package decorator.dec;
//豆奶
public class Soy extends CondimentDecorator {public Soy(Beverage beverage) {this.beverage=beverage;}@Overridepublic String getDescription() {return beverage.getDescription() + ",Soy";}public double cost() {return 1+beverage.cost();}
}
package decorator.dec;
//大小
public class Size extends CondimentDecorator {public Size(Beverage beverage,int size) {this.beverage = beverage;this.size=size;}@Overridepublic String getDescription() {// TODO 自动生成的方法存根if(size == beverage.TALL) {return beverage.getDescription() + ",小杯";}else if(size == beverage.GRANDE) {return beverage.getDescription() + ",中杯";}else if(size == beverage.WENTI) {return beverage.getDescription() + ",大杯";}return null;}@Overridepublic double cost() {double cost = beverage.cost();if(size == beverage.TALL) {cost += 0.1;}else if(size == beverage.GRANDE) {cost +=0.2;}else if(size == beverage.WENTI) {cost +=0.3;}return cost;}}
package decorator.dec;
//搅拌
public class Whip extends CondimentDecorator {//Noodle beverage;public Whip(Beverage beverage) {this.beverage=beverage;}@Overridepublic String getDescription() {return beverage.getDescription() + ",Whip";}public double cost() {return 1+beverage.cost();}
}
        2.1.5  main方法实现装饰者模式
package decorator.dec;public class Test {public static void main(String[] args) {// TODO 自动生成的方法存根Beverage beverage1 =new Mocha(new milk(new DarkRoast()));System.out.println(beverage1.getDescription()+" 合计$"+beverage1.cost());Beverage beverage2 =new Mocha(new milk(new DarkRoast()));Beverage beverage3 =new Size(new Mocha(new milk(new DarkRoast())),2);Beverage size = new Size(beverage2,2);System.out.println(size.getDescription()+" 合计$"+size.cost());}
}
        2.1.6 UML图

        2.2 窗口显示
        2.2.1 抽象构件(抽象基类:显示构件Component)
package decorator.visualCompanent;
//显示构件
public abstract class Component {public abstract void display();
}
        2.2.2 具体构件(列表框、文本框、窗体)
package decorator.visualCompanent;public class ListBox extends Component {@Overridepublic void display() {// TODO 自动生成的方法存根System.out.println("显示列表框!");}}
package decorator.visualCompanent;public class TextBox extends Component {@Overridepublic void display() {// TODO 自动生成的方法存根System.out.println("显示文本框!");}}
package decorator.visualCompanent;public class Window extends Component {@Overridepublic void display() {// TODO 自动生成的方法存根System.out.println("显示窗体!");}}
         2.2.3 抽象装饰类(ComponentDecorator)
package decorator.visualCompanent;public class ComponentDecorator extends Component{private Component component;//维持对抽象构件类型对象的引用//注入抽象构件类型的对象public ComponentDecorator(Component component) {this.component = component;}public void display() {component.display();}
}
          2.2.4 具体装饰类(增加新的构件:黑色边框和滚动条)
package decorator.visualCompanent;public class BlackBorderDecorator extends ComponentDecorator {public BlackBorderDecorator(Component component) {super(component);}public void display() {// TODO 自动生成的方法存根this.setBlackBorder();super.display();}public void setBlackBorder() {System.out.println("为构件增加黑色边框!");}
}
package decorator.visualCompanent;public class ScrollBarDecorator extends ComponentDecorator {public ScrollBarDecorator(Component component) {super(component);}public void display() {// TODO 自动生成的方法存根this.setScrollBar();super.display();}public void setScrollBar() {System.out.println("为构件增加滚动条!");}}
        2.2.5 main方法实现装饰者模式
package decorator.visualCompanent;public class Client {public static void main(String[] args) {// TODO 自动生成的方法存根//使用抽象构件定义全部对象Component component,componentSB,componentBB;component = new Window(); //创建具体对象//创建装饰后的构件对象componentSB = new ScrollBarDecorator(component);//将装饰了一次的对象componentBB = new BlackBorderDecorator(componentSB);componentBB.display();}}
        2.2.6 UML图

三、代码结构图

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LCR 039

. - 力扣(LeetCode). - 备战技术面试?力扣提供海量技术面试资源,帮助你高效提升编程技能,轻松拿下世界 IT 名企 Dream Offer。https://leetcode.cn/problems/0ynMMM/ 给定非负整数数组 heights ,数组中的数字用来表示…

AtCoder Beginner Contest 340

前面两道阅读理解直接跳过 C - Divide and Divide 大意 黑板上有一个数。 执行下列操作,直到黑板上的数全为1: 选择一个不小于2的整数,擦掉。写下和。需要的代价。 当不能继续操作时,总代价是多少? 思路 定义表示黑板上初…

【数学建模】优劣解距离法Topsis模型(含MATLAB代码)

TOPSIS法,全称 Technique for Order Preference by Similarity to an Ideal Solution,是由C.L.Hwang和K.Yoon于1981年首次提出的 。这是一种多目标决策分析中常用的有效方法,也被称作优劣解距离法 。 TOPSIS法的基本原理是通过检测评价对象与…

网盘_游戏_博客自动化部署(Nginx多项目部署)

目录 一.前提介绍 二.环境介绍 三.自述(脚本) 四.关于Nginx多项目部署 一.前提介绍 在我之前的博客里详细介绍了上述项目的部署,那么如何使用简单脚本自动部署和使用Nginx多项目部署是本文来介绍的基础篇章。 二.环境介绍 CentOS Linux…

书生·浦语2.0(InternLM2)大模型实战--Day04 XTuner微调 | 1.8B 多模态Agent(Part 2: 多模态部分)

视频地址: https://b23.tv/QUhT6ni课程文档:https://github.com/InternLM/Tutorial/blob/camp2/xtuner/readme.md作业文档:https://github.com/InternLM/Tutorial/blob/camp2/xtuner/homework.md 1. XTuner多模态训练与测试 在本节课中&…

[已解决]react打包部署

react打包部署 问题 npm install 命令无反应 思路 换成 yarn install 安装完hadoop的环境后,使用node的yarn会报错: 我们在cmd使用where yarn,如下: 看你想保留哪一个,我平时node用的多,就把hadoop的y…

Spring Boot中接收各种各样的参数

一、接收json参数&#xff0c;封装为Map 1.1、核心代码 /*** 接收json参数&#xff0c;封装为Map* param servletRequest* return* throws Exception*/ PostMapping("/getParam") public R getParam(HttpServletRequest servletRequest) throws Exception {Map<…

mysql基础19——日志

日志 mysql的日志种类非常多 通用查询日志 慢查询日志 错误日志 与时间有关联 二进制日志 中继日志 与主从服务器的同步有关 重做日志 回滚日志 与数据丢失有关 通用查询日志 记录了所有用户的连接开始时间和截至时间 以及给mysql服务器发送的所有指令 当数据异常时&…

个人开发 App 最简单方法:使用现代开发工具和平台

在移动应用市场的蓬勃发展下&#xff0c;个人开发者也有机会将自己的创意转化为实际的应用程序&#xff0c;并通过应用商店实现盈利。然而&#xff0c;对于许多初学者来说&#xff0c;如何开始个人开发一个应用可能会感到困惑。本文将介绍个人开发 App 的最简单方法&#xff0c…

C++修炼之路之list--C++中的双向循环链表

目录 前言 一&#xff1a;正式之前先回顾数据结构中的双向循环链表 二&#xff1a;list的简介 三&#xff1a;STL中list常用接口函数的介绍及使用 1.构造函数接口 2.list迭代器 范围for 3.数据的修改接口函数 4.list容量操作函数 5.list的迭代器失效 6.演示代码和测…

独立样本t检验——python完整代码(直接运行就行)

#!/usr/bin/env python # -*- coding: utf-8 -*- # Author : 三十二画生JH # Contact : fjhstudent163.com # Software: PyCharm # Time : 2024/4/21 21:49 # Site : 网址 # File : t_test.py # Version : # ---功能描述 """ 对实验数据做独立样本&am…

Linux系统维护:增加空闲内存的大小,以便进程有足够的基础内存(空闲内存)来运行

目录 一、问题 二、解决思路 &#xff08;一&#xff09;问题分析 &#xff08;二&#xff09;思路 1. 清理缓存 2. 结束不必要的进程 3. 优化应用程序和服务 4. 增加物理内存 5、注意事项 三、实际处理 &#xff08;一&#xff09;结束不必要的程序 &#xff08;二…