23种设计模式之一— — — —装饰模式详细介绍与讲解

装饰模式详细讲解

一、定义

装饰模式(别名:包装器)

装饰模式(Decorator Pattern)是结构型的设计模式,它允许在运行时动态地向对象添加新的职责或功能,同时保持对象的原始类不变。通过使用装饰器模式,可以在不修改现有代码的基础上扩展对象的功能,

二、装饰模式结构

核心思想

1.动态扩展 :在不改变原类结构和继承关系的情况下,动态地为对象添加功能。
2.包装对象 :通过创建一个包装对象(装饰器)来包裹真实对象,增加额外功能。
3.接口一致性 :装饰器与真实对象有相同的接口,确保客户端能以相同的方式与两者交互。
4.开闭原则 :对扩展开放,对修改关闭。新的功能通过添加装饰器实现,而不是修改原类。
5.灵活组合:允许通过组合多个装饰器来创建功能更为丰富的对象

模式角色

1.抽象组件(Component) :定义一个接口,用于规范准备接收附加责任的对象(即被装饰对象)。
2.具体组件(ConcreteComponent) :实现抽象组件接口,是装饰器要装饰的真实对象。
3.装饰器(Decorator) :持有一个抽象组件的引用,并继承抽象组件的接口。它既可以使用所持有的引用调用被装饰的组件的方法,也可以增加新的功能。
4.具体装饰器(ConcreteDecorator) :实现装饰器接口并给具体组件添加职责。它通常包含对具体组件的引用,以及一个或多个用于增加功能的额外方法。

这些角色在装饰模式中的交互方式是:

  • 抽象组件定义了所有装饰器对象和被装饰对象需要实现的接口。
  • 具体组件实现了抽象组件接口,是准备被装饰的对象。
  • 装饰器持有一个对抽象组件的引用,并且实现了抽象组件接口。它可以使用这个引用来调用被装饰对象的方法,并在调用前后添加新的功能。
  • 具体装饰器实现了装饰器接口,并且给具体组件添加新的职责。它通常包含一个指向被装饰对象的引用,以及用于实现附加功能的代码。

模式的UML类图

应用场景

  • 当需要为单个对象提供多种不同的行为或者表现形式时。
  • 需要向一个已经存在的类中添加功能,但又不希望修改该类的源代码或继承其子类时
  • 组合对象:当需要组合多个对象来创建一个具有更多功能的对象时,装饰模式是一个很好的选择。通过递归组合方式,可以构建出一个具有多种功能的对象。例如,在文件系统中,文件夹可以被视为一个特殊的文件,它可以包含其他文件和文件夹。使用装饰模式,可以将文件夹装饰为一个包含额外功能的对象,如支持加密、压缩等

模式优点

  • 动态地给对象添加功能,相比生成子类更加灵活、透明。
  • 无需修改原有类就可以扩展功能,符合开闭原则。
  • 装饰器可以被组合,以便在运行时动态地、多次地添加多个职责。

模式缺点

  • 这种比继承更加灵活机动的特性,也同时意味着更加多的复杂性。
  • 装饰模式会导致设计中出现许多小类,如果过度使用,会使程序变得很复杂。
  • 不易调试:由于装饰器模式涉及到多个对象的交互,调试可能会变得相对困难。特别是当装饰器链很长时,追踪请求和响应的路径可能会变得复杂。

实例演示

图示

鸡腿堡应用:

代码演示

java 复制代码
package ZhuangShiMoShi;

public abstract class Humburger {
	protected String name;

	public String getName() {
		return name;
	}

	public abstract double getPrice();

}

package ZhuangShiMoShi;

public class ChickenBurger extends Humburger {
	public ChickenBurger(){
		name="鸡腿堡";
	}
	public double getPrice(){
		return 10;
	}
	

}

package ZhuangShiMoShi;

public abstract class Condiment extends Humburger {
	protected Humburger humburger;
	public abstract String getName();

}

package ZhuangShiMoShi;

public class Chilli extends Condiment {
	public Humburger hum;

	public Chilli(Humburger hum) {
		this.hum = hum;
	}

	@Override
	public String getName() {
		// TODO Auto-generated method stub
		return hum.getName() + " 加辣椒";
	}

	@Override
	public double getPrice() {
		// TODO Auto-generated method stub
		return hum.getPrice();
	}

}

package ZhuangShiMoShi;

public class Lettuce extends Condiment {
	public Humburger hum;

	public Lettuce(Humburger hum) {
		this.hum = hum;
	}

	@Override
	public String getName() {
		// TODO Auto-generated method stub
		return hum.getName()+" 加生菜";
	}

	@Override
	public double getPrice() {
		// TODO Auto-generated method stub
		return hum.getPrice()+1.5;
	}

}

测试类:

java 复制代码
package ZhuangShiMoShi;

public class Test {
	public static void main(String[] args) {
		Humburger hum = new ChickenBurger();
		System.out.println(hum.getName() + " 价钱:" + hum.getPrice());
		Lettuce lettuce=new Lettuce(hum);
		System.out.println(lettuce.getName()+" 价钱:"+lettuce.getPrice());
		Chilli chilli1=new Chilli(hum);
		System.out.println(chilli1.getName()+" 价钱:"+chilli1.getPrice());
		Chilli chilli2=new Chilli(lettuce);
		System.out.println(chilli2.getName()+" 价钱:"+chilli2.getPrice());
	}

}

运行结果

该代码主体是鸡腿堡,可以选择通过添加生菜、酱、辣椒等等许多其他的配料,并根据选择的配料计算相应的价格。
博主用心写,读者点关注;互动传真情,知识不迷路

相关推荐
信仰_2739932436 分钟前
RocketMQ事务消息实现订单创建 + 扣减库存
java·rocketmq·java-rocketmq
百***58146 分钟前
Spring Boot 2.7.x 至 2.7.18 及更旧的版本,漏洞说明
java·spring boot·后端
q***64971 小时前
Spring BOOT 启动参数
java·spring boot·后端
百***78451 小时前
Java实战:Spring Boot application.yml配置文件详解
java·网络·spring boot
你不是我我1 小时前
【Java 开发日记】SQL 语句左连接右连接内连接如何使用,区别是什么?
java·javascript·数据库
七夜zippoe1 小时前
Java性能调优工具篇:JMH基准测试与Profiler(JProfiler/Async-Profiler)使用指南
java·开发语言·jprofiler·jmh·async-profiler
從南走到北1 小时前
JAVA国际版二手车交易二手车市场系统源码支持Android+IOS+H5+APP
android·java·ios
Kuo-Teng2 小时前
LeetCode 19: Remove Nth Node From End of List
java·数据结构·算法·leetcode·链表·职场和发展·list
北i2 小时前
TiDB 关联子查询去关联优化实战案例与原理深度解析
java·数据库·sql·tidb
Kuo-Teng2 小时前
LeetCode 21: Merge Two Sorted Lists
java·算法·leetcode·链表·职场和发展