设计模式-第4章(装饰模式)

news2024/9/27 9:29:02

装饰模式

  • 装饰模型
  • 装饰模式示例
  • 商场收银程序(简单工厂+策略+装饰模式实现)
  • 装饰模式总结

装饰模型

装饰模式(Decorator),动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活。
在这里插入图片描述
Component 是定义一个对象接口,可以给这些对象动态地添加职责。
ConcreateComponent 是定义了一个具体的对象,也可以给这个对象添加一些职责。
Decorator,装饰抽象类,继承了 Component,从外类来扩展 Component 类的功能,但对应Component 来说,是无须知道 Decorator的存在。
ConcreateDecorator 就是具体的装饰对象,起到给 Component 添加职责的功能。

// Component类
abstract class Component {
    public abstract void Operation();
}
// ConcreteComponent类
class ConcreteComponent extends Component {
    public void Operation() {
        System.out.println("具体对象的实际操作");
    }
}
//Decorator类
abstract class Decorator extends Component {

    protected Component component;

    //装饰一个Component对象
    public void SetComponent(Component component) {
        this.component = component;
    }
    //重写Operation(),实际调用component的Operation方法
    public void Operation() {
        if (component != null) {
            component.Operation();
        }
    }
}
//ConcreteDecoratorA类
class ConcreteDecoratorA extends Decorator {
    //本类独有子段,以区别于ConcreteDecoratorB类
    private String addedState;
    public void Operation() {
    	//首先运行了原有Component的Operation()
        super.Operation();
        this.addedState = "具体装饰对象A的独有操作";
        //再执行本类独有功能
        System.out.println(this.addedState);

    }
}
//ConcreteDecoratorB类
class ConcreteDecoratorB extends Decorator {
    public void Operation() {
    	//首先运行了原有Component的Operation()
        super.Operation();
        //再执行本类独有功能
        this.AddedBehavior();
    }
    //本类独有方法,以区别于ConcreteDecoratorA类
    private void AddedBehavior() { 
    	System.out.println("具体装饰对象B的独有操作");
    }
}

客户端代码

public class Test {
	public static void main(String[] args){
		System.out.println("**********************************************");		
		System.out.println("《大话设计模式》代码样例");
		System.out.println();		
		ConcreteComponent c = new ConcreteComponent();
    	ConcreteDecoratorA d1 = new ConcreteDecoratorA();
    	ConcreteDecoratorB d2 = new ConcreteDecoratorB();
    	//首先用d1来包装c,扩展对象c的方法
    	d1.SetComponent(c);	
    	//再用有来包装d1,扩展对象d1的方法
    	d2.SetComponent(d1);
    	//最终执行d2的Operation()
    	d2.Operation();   	
		System.out.println();
		System.out.println("**********************************************");
	}
}

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

如果只有一个ConcreteComponent 类而没有抽象的 Component 类,那么 Decorator 类可以是 ConcreteComponent 的一个子类。
同样道理,如果只要一个 ConcreteDecorator 类,那么就没有必要建立一个单独的 Decorator 类,而可以把 Decorator 和 ConcreteDecorator 的责任合并成一个类。

装饰模式示例

在这里插入图片描述
人物形象接口

public interface ICharacter {
   public void show();
}

具体人类

public class Person implements ICharacter {
	private String name;
    public Person(String name) {
        this.name = name;
    }
    public void show() {
        System.out.println("装扮的"+name);
    }
}

服饰类

public class Finery implements ICharacter {

    protected ICharacter component;

    public void decorate(ICharacter component) {
        this.component=component;
    }
    public void show() {
        if (this.component != null){
            this.component.show();
        }
    }
}

具体服饰类(ConcreteDecorator)

public class LeatherShoes extends Finery {
    public void show(){
        System.out.print(" 皮鞋");
        super.show();
    }
}
public class BigTrouser extends Finery {
    public void show(){
        System.out.print(" 垮裤");
        super.show();
    }
}
public class TShirts extends Finery {
    public void show(){
        System.out.print(" 大T恤");
        super.show();
    }
}
public class Tie extends Finery {
    public void show(){
        System.out.print(" 领带");
        super.show();
    }
}
public class Suit extends Finery {
    public void show(){
        System.out.print(" 西装");
        super.show();
    }
}
public class Strawhat extends Finery {
    public void show(){
        System.out.print(" 草帽");
        super.show();
    }
}
public class Sneakers extends Finery {
    public void show(){
        System.out.print(" 球鞋");
        super.show();
    }
}

客户端代码

public class Test {
	public static void main(String[] args){
		System.out.println("**********************************************");		
		System.out.println("《大话设计模式》代码样例");
		System.out.println();		

		Person xc = new Person("小菜");
        System.out.println(" 第一种装扮:");
        Sneakers pqx = new Sneakers();      //生成球鞋实例
        pqx.decorate(xc);                   //球鞋装饰小菜
        BigTrouser kk = new BigTrouser();   //生成垮裤实例
        kk.decorate(pqx);                   //垮裤装饰“有球鞋装饰的小菜”
        TShirts dtx = new TShirts();        //生成T恤实例
        dtx.decorate(kk);                   //T恤装饰“有垮裤球鞋装饰的小菜”
        dtx.show();                         //执行形象展示

        System.out.println(" 第二种装扮:");
        LeatherShoes px = new LeatherShoes();//生成皮鞋实例
        px.decorate(xc);                    //皮鞋装饰小菜
        Tie ld = new Tie();                 //生成领带实例
        ld.decorate(px);                    //领带装饰“有皮鞋装饰的小菜”
        Suit xz = new Suit();               //生成西装实例
        xz.decorate(ld);                    //西装装饰“有领带皮鞋装饰的小菜”
        xz.show();                          //执行形象展示
        
        System.out.println(" 第三种装扮:");
        Sneakers pqx2 = new Sneakers();     //生成球鞋实例
        pqx2.decorate(xc);                  //球鞋装饰小菜
        LeatherShoes px2 = new LeatherShoes();//生成皮鞋实例
        px2.decorate(pqx2);                 //皮鞋装饰“有球鞋装饰的小菜”
        BigTrouser kk2 = new BigTrouser();  //生成垮裤实例
        kk2.decorate(px2);                  //垮裤装饰“有皮鞋球鞋装饰的小菜”
        Tie ld2 = new Tie();                //生成领带实例
        ld2.decorate(kk2);                  //领带装饰“有垮裤皮鞋球鞋装饰的小菜”
        Strawhat cm2 = new Strawhat();      //生成草帽实例
        cm2.decorate(ld2);                  //草帽装饰“有领带垮裤皮鞋球鞋装饰的小菜”
        cm2.show();                         //执行形象展示

		System.out.println();
		System.out.println("**********************************************");
	}
}

商场收银程序(简单工厂+策略+装饰模式实现)

在这里插入图片描述
ISale接口:用作装饰模式里的 Component。
CashNormal: 用作装饰模式里的 ConcreteComponent。
CashSuper: 用作装饰模式里的 Decorator 。
CashReturn:用作装饰模式里的 ConcreateDecorator 。

public interface ISale {
   public double acceptCash(double price,int num);
}
// 正常收费,原价返回
public class CashNormal implements ISale {
    public double acceptCash(double price,int num){
        return price * num;
    }
}
public class CashSuper implements ISale {

    protected ISale component;

    //装饰对象
    public void decorate(ISale component) {
        this.component=component;
    }

    public double acceptCash(double price,int num){
        var result = 0d;
        if (this.component != null){
            //若装饰对象存在,则执行装饰的算法运算
            result = this.component.acceptCash(price,num);    
        }
        return result;
    }
}
public class CashRebate extends CashSuper {
    private double moneyRebate = 1d;
    //打折收费。初始化时必需输入折扣率。八折就输入0.8
    public CashRebate(double moneyRebate){
        this.moneyRebate = moneyRebate;
    }
    //计算收费时需要在原价基础上乘以折扣率
    public double acceptCash(double price,int num){
        double result = price * num * this.moneyRebate;
        return super.acceptCash(result,1);
    }
}

public class CashReturn extends CashSuper {
    private double moneyCondition = 0d; //返利条件
    private double moneyReturn = 0d;    //返利值

    //返利收费。初始化时需要输入返利条件和返利值。
    //比如“满300返100”,就是moneyCondition=300,moneyReturn=100
    public CashReturn(double moneyCondition,double moneyReturn){
        this.moneyCondition = moneyCondition;
        this.moneyReturn = moneyReturn;
    }
    //计算收费时,当达到返利条件,就原价减去返利值
    public double acceptCash(double price,int num){
        double result = price * num;
        if (moneyCondition>0 && result >= moneyCondition)
            result = result - Math.floor(result / moneyCondition) * moneyReturn; 
        return super.acceptCash(result,1);   
    }   
}
public class CashContext {
    private ISale cs;   //声明一个ISale接口对象    
    //通过构造方法,传入具体的收费策略
    public CashContext(int cashType){
        switch(cashType){
            case 1:
                this.cs = new CashNormal();
                break;
            case 2:
                this.cs = new CashRebate(0.8d);
                break;
            case 3:
                this.cs = new CashRebate(0.7d);
                break;
            case 4:
                this.cs = new CashReturn(300d,100d);
                break;
            case 5:
                //先打8折,再满300返100
                // 装饰模式
                CashNormal cn = new CashNormal();
                CashReturn cr1 = new CashReturn(300d,100d); 
                CashRebate cr2 = new CashRebate(0.8d);
                cr1.decorate(cn);   //用满300返100算法包装基本的原价算法
                cr2.decorate(cr1);  //打8折算法装饰满300返100算法
                this.cs = cr2;      //将包装好的算法组合引用传递给cs对象
                break;
            case 6:
                //先满200返50,再打7折
                // 装饰模式
                CashNormal cn2 = new CashNormal();
                CashRebate cr3 = new CashRebate(0.7d);
                CashReturn cr4 = new CashReturn(200d,50d); 
                cr3.decorate(cn2);  //用打7折算法包装基本的原价算法
                cr4.decorate(cr3);  //满200返50算法装饰打7折算法
                this.cs = cr4;      //将包装好的算法组合引用传递给cs对象
                break;
        }
    }
    public double getResult(double price,int num){
        // 根据收费策略的不同,获得计算结果
        return this.cs.acceptCash(price,num);
    }    
}

客户端代码

public class Test {
	public static void main(String[] args){
		System.out.println("**********************************************");		
		System.out.println("《大话设计模式》代码样例");
		System.out.println();		

		int discount = 0; 		//商品折扣模式
		double price = 0d; 		//商品单价
		int num = 0;			//商品购买数量
		double totalPrices = 0d;//当前商品合计费用
		double total = 0d;		//总计所有商品费用
		Scanner sc = new Scanner(System.in);
		do {
			System.out.println("商品折扣模式如下:");	
			System.out.println("1.正常收费");	
			System.out.println("2.打八折");	
			System.out.println("3.打七折");	
			System.out.println("4.满300送100");	
			System.out.println("5.先打8折,再满300送100");	
			System.out.println("6.先满200送50,再打7折");	
			System.out.println("请输入商品折扣模式:");	
			discount = Integer.parseInt(sc.nextLine());
			System.out.println("请输入商品单价:");	
			price = Double.parseDouble(sc.nextLine());
			System.out.println("请输入商品数量:");	
			num = Integer.parseInt(sc.nextLine());
			System.out.println();	
			if (price>0 && num>0){
				//根据用户输入,将对应的策略对象作为参数传入CashContext对象中
				CashContext cc = new CashContext(discount);
				//通过Context的getResult方法的调用,可以得到收取费用的结果
				//让具体算法与客户进行了隔离
				totalPrices = cc.getResult(price,num);
				total = total + totalPrices;
				
				System.out.println();	
				System.out.println("单价:"+ price + "元 数量:"+ num +" 合计:"+ 
									totalPrices +"元");	
				System.out.println();
				System.out.println("总计:"+ total+"元");	
				System.out.println();
			}
		}while(price>0 && num>0);
		System.out.println();
		System.out.println("**********************************************");
	}
}

装饰模式总结

装饰模式是为已有功能动态地添加更多功能的一种方式。

当系统需要新功能的时候,是向旧的类中添加新的代码。这些新加的代码通常装饰了原有类的核心职责或主要行为,但这种做法的问题在于,它们在主类中加入了新的字段,新的方法和新的逻辑,从而增加了主类的复杂度。
装饰模式却提供了一个非常好的解决方案,它把每个要装饰的功能放在单独的类中,并让这个类包装它所要装饰的对象,因此,当需要执行特殊行为时,客户代码就可以在运行时根据需要有选择地、按顺序地使用装饰功能包装对象了。

把类中的装饰功能从类中搬移去除,这样可以简化原有的类。这样做的好处就是有效地把类的核心职责和装饰功能区分开了。

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

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

相关文章

【基础算法】双指针----字符串删减

🌹作者:云小逸 📝个人主页:云小逸的主页 📝Github:云小逸的Github 🤟motto:要敢于一个人默默的面对自己,强大自己才是核心。不要等到什么都没有了,才下定决心去做。种一颗树,最好的时间是十年前…

Java查漏补缺(13)泛型概述、使用泛型举例、自定义泛型结构、泛型在继承上的体现、通配符的使用

Java查漏补缺(13)泛型概述、使用泛型举例、自定义泛型结构、泛型在继承上的体现、通配符的使用本章专题与脉络1. 泛型概述1.1 生活中的例子1.2 泛型的引入2. 使用泛型举例2.1 集合中使用泛型2.1.1 举例2.1.2 练习2.2 比较器中使用泛型2.2.1 举例2.2.2 练…

Vue下载安装步骤的详细教程(亲测有效) 2 安装与创建默认项目

上篇请移步到Vue下载安装步骤的详细教程(亲测有效) 1_水w的博客-CSDN博客 上一篇博文已经对Node.js的安装与配置进行了详细介绍。 另外:文中项目存放的路径及项目名称可根据自身实际情况进行更改。 目录 三、Vue安装配置 1、搭建Vue脚手架 2、通过NPM安装Vue …

二手商品交易网站

技术:Java、JSP等摘要:随着科学技术和信息通讯的飞速发展,Internet极大地丰富和改变着我们生活的各个行业。随着Internet的普及应用,人们可以跨越时间和空间的限制,足不出户便能通过网络完成信息交流,而完成…

Windows如何查看某个端口被占用的情况?

在工作中,有时会发现端口被占用的情况,导致软件报错或者服务无法启动等问题。在不知道具体哪个进程占用该端口号的情况下,我们可以用下面方法来查找。 举例:我现在发现8090端口被占用了,我现在需要找到并杀掉该进程。…

ICA简介:独立成分分析

1. 简介 您是否曾经遇到过这样一种情况:您试图分析一个复杂且高度相关的数据集,却对信息量感到不知所措?这就是独立成分分析 (ICA) 的用武之地。ICA 是数据分析领域的一项强大技术,可让您分离和识别多元数据集中的底层独立来源。 …

嵌入式 STM32 红外遥控

目录 红外遥控 NEC码的位定义 硬件设计 软件设计 源码程序 红外遥控 红外遥控是一种无线、非接触控制技术,具有抗干扰能力强,信息传输可靠,功耗低,成本低,容易实现等显著的特点,被诸多电子设备特别…

二进制、十六进制和浮点数ASCII的转换机制--------IEEE754

我在使用GPS时,通过网口接收到了BESTPOS格式的输出结果,它以16进制表示。 当前常见的GPS都以ASCII表示,例如我们在串口助手中可以选择输出类型为ASCII或者是16进制,那么说明它们中见肯定存在某种转换机制,既可以表示出…

javaEE 初阶 — 网络层 IP 协议 的功能 — 路由选择与地址管理

文章目录IP 协议的功能1.IP 协议的路由选择2.IP 协议的地址管理2.1 网络号与主机号的分界2.2 特殊 IPIP 协议的功能 网络层主要做两件事: 地址管理 路由选择 网络层的代表就是 IP 协议 网络层主要是负责管理路由设备,要从两个结点之间找到一条具体的…

01 presto 概述: 特性 优缺点 场景 架构

文章目录1. Presto是什么2. Presto优缺点2.1. 优点2.2. 缺点3. Presto适用场景4. Presto数据模型5. Presto 架构5.1 执行流程关键词:MPP 多源 即席查询 统一SQL执行引擎 分布式SQL引擎 数据分析 1. Presto是什么 Presto是一款开源的分布式并行计算(MPP)引擎&#x…

Hive基础命令

一、Hive其他命令 1、在hive cli命令窗口中如何查看hdfs文件系统 dfs -ls /;2、在hive cli命令窗口中如何查看本地文件系统 !ls /opt;二、Hive数据类型 1、基本数据类型 红标为常用的数据类型; 对于Hive的String类型相当于数据库的varchar类型,该类型…

python之web自动化测试框架

梳理下搭建web自动化框架的流程: 创建目录: cases:存放测试用例,unittest框架要求用例名必须以test开头,所以命名test_case.py test_case.py代码如下:继承unittest.TestCase类下面的方法setupclass(),te…

优思学院|精益生产现场管理的要素是什么?

精益生产的目的是通过消除3M来实现生产过程的优化和精简。3M指的是 "Muda"、"Muri"、"Mura",这三个词来自于日本,代表了生产过程中的浪费、超负荷和不平衡。 因此,要消除3M,优思学院认为企业精益生…

qt-c++进阶1-window、linux下获取本机所有网卡ip信息、根据网卡名获取ip地址。

系列文章目录 例如:第一章 主要是通过qt-c实现获取本机电脑的网卡信息或者是IP信息 文章目录系列文章目录前言一、获取本机网卡IP信息1.1 获取ip地址方法1.2 代码实例总结前言 总结c获取本机网卡信息的方法 第一章:适用于windows操作系统、linux操作系…

中级嵌入式系统设计师2015下半年下午应用技能试题

中级嵌入式系统设计师2015下半年下午试题 试题一 阅读以下关于某嵌入式系统设计的说明,回答下列问题。 [说明] 某公司承接了某嵌入式系统的研制任务。该嵌入式系统由数据处理模块、系统管理模块、FC网络交换模块和智能电源模块组成,系统组成如图1所示。数据处理模块处理系统…

Linux 练习三 (Makefile工程管理器)

文章目录Makefile工程管理器第一个makefile:编写两个.c源文件,并且让一个调用另外一个,使用makefile建立依赖,生成可执行文件,并执行。伪目标变量预定义变量和自动变量通配符和模式匹配内置函数循环指定makefile文件综…

js数组格式字符串处理

文章目录一. 前言二. 数组还原1. 方法一2. 方法二3. 方法三4. 方法四一. 前言 由于数据传输的问题我们常常在请求后拿到数组格式的字符串,一般情况分为以下四种: let str1 ["a","b","c","d"]; // 类型一 let…

【异常解决】The coordinator is not available

问题 最近上线跑了一个flink任务,运行不久,就会挂掉,初步查看日志报错如下 WARN org.apache.flink.connector.kafka.source.reader.KafkaSourceReader [] - Failed to commit consumer offsets for checkpoint 1 org.apache.kafka.clients…

IGBT窄脉冲现象

IGBT窄脉冲现象 tips:资料来自知乎 英飞凌《IGBT窄脉冲现象解读》 IGBT窄脉冲现象 1.什么是窄脉冲现象? 2.窄脉冲现象的原因 3.双脉冲测试IGBT窄脉冲开通 4.FWD窄脉冲开通 1.什么是窄脉冲现象? IGBT作为一种功率开关,从门级信号到器件开关过程…

用Python制作邮件检测器

github地址: https://github.com/CaLlMeErIC/MailDetective 因为需求需要写一个简单的邮件检测系统的框架,这里记录下思路 首先第一反应,这个检测系统不应该是各个邮件收件系统都有自带的吗,于是搜索了下是否有相关的邮件检测开源软件&#…