装饰模式解析:基本概念和实例教程
创作时间:
作者:
@小白创作中心
装饰模式解析:基本概念和实例教程
引用
CSDN
1.
https://blog.csdn.net/2301_82095378/article/details/140184788
装饰模式是一种常用的设计模式,它允许在不改变原有对象结构的情况下,动态地给对象添加新的功能。本文将详细介绍装饰模式的基本概念、结构、应用场景以及优缺点,并通过一个具体的咖啡制作系统案例,帮助读者更好地理解和掌握装饰模式的使用方法。
装饰模式
装饰模式,又称装饰者模式、装饰器模式,是一种结构型设计模式,允许你通过将对象放入包含行为的特殊封装对象中来为原对象绑定新的行为。
装饰模式结构
- 部件(Component):声明封装器和被封装对象的公用接口。
- 具体部件(Concrete Component):类是被封装对象所属的类。它定义了基础行为,但装饰类可以改变这些行为。
- 基础装饰(Base Decorator):类拥有一个指向被封装对象的引用成员变量。该变量的类型应当被声明为通用部件接口,这样它就可以引用具体的部件和装饰。装饰基类会将所有操作委派给被封装的对象。
- 具体装饰类(Concrete Decorators):定义了可动态添加到部件的额外行为。具体装饰类会重写装饰基类的方法,并在调用父类方法之前或之后进行额外的行为。
- 客户端(Client):可以使用多层装饰来封装部件,只要它能使用通用接口与所有对象互动即可。
通用代码结构示例:
//部件(设计之禅中提到成绩单)
interface Component{
void execute();
...
}
//具体部件 (4年级成绩单)
class ConcreteComponent implements Component{
@Override
public void execute(){
...
}
}
//基础装饰类
class BaseDecorator implements Component{
private Component c;
public BaseDecorator(Component c){
this.c=c;
}
@Override
public void execute(){
...
}
}
//具体装饰类
class ConcreteDecorators extends{
public ConcreteDecorators(Component c){
super(c);
}
public void extra(){
...
}
@Override
public void execute(){
this.extra();
super.execute();
...
}
}
//客户端
public class Client{
Component c = new ConcreteComponent();
c = new ConcreteDecorators();
c.excute();
...
}
装饰模式应用场景
- 如果你希望在无需修改代码的情况下即可使用对象,且希望在运行时为对象新增额外的行为,可以使用装饰模式。装饰能将业务逻辑组织为层次结构,你可为各层创建一个装饰,在运行时将各种不同逻辑组合成对象。由于这些对象都遵循通用接口,客户端代码能以相同的方式使用这些对象。
- 如果用继承来扩展对象行为的方案难以实现或者根本不可行,你可以使用该模式。许多编程语言使用final关键字来限制对某个类的进一步扩展。复用最终类已有行为的唯一方法是使用装饰模式:用封装器对其进行封装。
- 识别方法:装饰可通过以当前类或对象为参数的创建方法或构造函数来识别。
装饰模式优缺点
装饰模式优点:
- 你无需创建新子类即可扩展对象的行为。
- 你可以在运行时添加或删除对象的功能。
- 你可以用多个装饰封装对象来组合几种行为。
- 单一职责原则。你可以将实现了许多不同行为的一个大类拆分为多个较小的类。
装饰模式缺点:
- 在封装器栈中删除特定封装器比较困难。
- 实现行为不受装饰栈顺序影响的装饰比较困难。
- 各层的初始化配置代码看上去可能会很糟糕。
练手题目
题目描述
小明喜欢品尝不同口味的咖啡,他发现每种咖啡都可以加入不同的调料,比如牛奶、糖和巧克力。他决定使用装饰者模式制作自己喜欢的咖啡。请设计一个简单的咖啡制作系统,使用装饰者模式为咖啡添加不同的调料。系统支持两种咖啡类型:黑咖啡(Black Coffee)和拿铁(Latte)。
输入描述
多行输入,每行包含两个数字。第一个数字表示咖啡的选择(1 表示黑咖啡,2 表示拿铁),第二个数字表示要添加的调料类型(1 表示牛奶,2 表示糖)。
输出描述
根据每行输入,输出制作咖啡的过程,包括咖啡类型和添加的调料。
题解
简单的装饰模式实现。
import java.util.Scanner;
// 定义咖啡接口
interface Coffee {
void execute();
}
// 黑咖啡类,实现咖啡接口
class BrewingBlackCoffee implements Coffee {
@Override
public void execute() {
System.out.println("Brewing Black Coffee");
}
}
// 拿铁类,实现咖啡接口
class BrewingLatte implements Coffee {
@Override
public void execute() {
System.out.println("Brewing Latte");
}
}
// 咖啡装饰器抽象类,实现咖啡接口
abstract class Decorator implements Coffee {
private Coffee coffee;
public Decorator(Coffee coffee) {
this.coffee = coffee;
}
@Override
public void execute() {
coffee.execute();
}
}
// 牛奶装饰器类,继承自装饰器类
class MilkDecorator extends Decorator {
public MilkDecorator(Coffee coffee) {
super(coffee);
}
@Override
public void execute() {
super.execute();
System.out.println("Adding Milk");
}
}
// 糖装饰器类,继承自装饰器类
class SugarDecorator extends Decorator {
public SugarDecorator(Coffee coffee) {
super(coffee);
}
@Override
public void execute() {
super.execute();
System.out.println("Adding Sugar");
}
}
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
try {
String input;
while (scanner.hasNextLine()) {
input = scanner.nextLine();
if (input.equalsIgnoreCase("exit")) {
break;
}
processInput(input);
}
} catch (NumberFormatException e) {
System.out.println("输入格式无效:" + e.getMessage());
} finally {
scanner.close();
}
}
// 处理输入的方法
private static void processInput(String input) {
String[] parts = input.split(" ");
if (parts.length != 2) {
System.out.println("输入格式无效。请提供两个数字,中间用空格分隔。");
return;
}
try {
int type1 = Integer.parseInt(parts[0]);
int type2 = Integer.parseInt(parts[1]);
Coffee coffee = createCoffee(type1);
if (coffee == null) {
System.out.println("咖啡类型无效。请输入1(黑咖啡)或2(拿铁)。");
return;
}
coffee = decorateCoffee(coffee, type2);
if (coffee == null) {
System.out.println("装饰类型无效。请输入1(牛奶)或2(糖)。");
return;
}
coffee.execute();
} catch (NumberFormatException e) {
System.out.println("输入格式无效:两个输入都必须是数字。");
}
}
// 创建咖啡对象的方法
private static Coffee createCoffee(int type) {
switch (type) {
case 1:
return new BrewingBlackCoffee();
case 2:
return new BrewingLatte();
default:
return null;
}
}
// 添加装饰器的方法
private static Coffee decorateCoffee(Coffee coffee, int type) {
switch (type) {
case 1:
return new MilkDecorator(coffee);
case 2:
return new SugarDecorator(coffee);
default:
return null;
}
}
}
热门推荐
芝麻黑豆浆走红:营养价值超猪肉鸡蛋,制作方法详解
家庭自制豆浆攻略:黄金比例+保存秘诀
湿疹新疗法:整合式心理治疗了解一下?
春风堂上新来燕,乔迁祝福满满
早安心语:赖床还是吃早餐?
用搞笑早安心语点亮你的朋友圈,成为最受欢迎的开心果
《植物大战僵尸2》二爷僵尸攻略:狂暴状态下的应对之道
朝阳医院检验科布局科研创新,将建三大研究团队
乔迁之喜,如何写出最暖心的祝福?
惠州公立医院眼科实力榜:哪家近视手术做得好?
上海三甲医院眼科实力榜:5家医院特色治疗与口碑
公函怎么写?5大原则+5个技巧,附完整范文解析
37公里灵渠联通湘漓,2000余年持续发挥水利功能
“世界船闸之父”灵渠:从秦代水利工程到国际遗产
2026世界运河大会将聚焦灵渠,展现中国生态文明建设成果
灵渠:中国古代水利工程奇迹,2026年将办世界运河大会
雷诺综合征的治疗方法
乔迁宴新玩法:灯光秀+美食趴,让新家闪耀又美味!
大量上市,分享6种大白菜的家常做法,照着做,每天饭桌不重样
汉字简化过犹不及:二简字运动何以折戟沉沙
顿号输入指南:Windows和Mac系统快捷键与插入方法
Windows 11取消顿号键,四种官方方案轻松解决
交通事故保险理赔全攻略:法律依据、索赔流程与保险过期处理
轮滑新手必看:掌握直线滑行技巧
海南万宁:中国冲浪之都的崛起与挑战
中华巴洛克街区:哈尔滨老道外的历史探秘
《宇宙护卫队》主题雪雕亮相哈尔滨冰雪大世界
哈尔滨冰雪大世界和雪乡,谁才是冬游首选?
Anna教你用问候语提升人际魅力
文旅部推荐:湖北最美小镇旅游路线