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());
	}

}

运行结果

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

相关推荐
海边漫步者13 分钟前
Idea2024中搭建JavaFX开发环境并创建运行项目
java·intellij-idea·javafx
Warren9823 分钟前
Springboot中分析SQL性能的两种方式
java·spring boot·后端·sql·mysql·intellij-idea
Distance失落心1 小时前
idea任意版本的安装
java·ide·java-ee·eclipse·intellij-idea
Aphelios3801 小时前
Linux 下 VIM 编辑器学习记录:从基础到进阶(下)
java·linux·学习·编辑器·vim
独孤求败Ace2 小时前
第46天:Web开发-JavaEE应用&原生和FastJson反序列化&URLDNS链&JDBC链&Gadget手搓
java·spring·java-ee
Ting-yu2 小时前
项目实战--网页五子棋(匹配模块)(4)
java
优人ovo2 小时前
3分钟idea接入deepseek
java·ide·intellij-idea
计算机学姐2 小时前
基于SpringBoot的校园消费点评管理系统
java·vue.js·spring boot·后端·mysql·spring·java-ee
猎人everest2 小时前
Spring Boot数据访问(JDBC)全解析:从基础配置到高级调优
java·spring boot·后端
m0_674031432 小时前
详解Tomcat下载安装以及IDEA配置Tomcat(2023最新)
java·tomcat·intellij-idea