装饰模式解析:基本概念和实例教程
创作时间:
作者:
@小白创作中心
装饰模式解析:基本概念和实例教程
引用
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;
}
}
}
热门推荐
种源创新“藏粮于技”
盆栽竹子养护大全(从浇水到修剪,让你的盆栽竹子更旺盛)
手机处理器性能之战:谁领风骚,谁主沉浮?
山西太原旅游攻略6日报团游,山西6日游大概花费多少?
汇率急速贬值下的日本黄金周:海外游客敢花,日本民众要“省”
如何合理评估农村征地补偿?这些评估标准有哪些实际应用?
昌图县十大旅游景点
好消息!铁路部门规定,60岁以上乘坐火车和高铁,可享受5个福利
美少女万华镜5莲华和夏彦前世是什么关系
老来骨头脆,打个喷嚏都会碎?如何科学补钙,医生有话说
五行相生相克与命理风水的奥秘
你是“安静型BPD”吗?——默默忍受的边缘型人格障碍
恶意别车的法律责任与量刑标准
网站迁移完全指南:从备份到测试的详细步骤
Qt学习第三篇(信号槽函数的连接)
现代中国教育体系中学生面临的心理健康挑战
如何获取 arXiv 邀请码及其重要性
曾一条卖至上千,如今却被吐槽穿着像“上刑”:失宠的牛仔裤,为何被抛弃?
周杰伦:华语乐坛的传奇常青树
大城市的生活成本和收入水平如何?大城市的生活质量和职业发展机会是什么?
权力的平衡术:三省六部制与古代中国的治理智慧
经常焦虑的人可以试一下这 7 种自我调节策略
《布鲁克林有棵树》——贫穷无法禁锢的成长力量
新能源汽车驱动电机构造、原理及关键技术
看肾脏好不好,从尿液就能看出来?什么样的尿液最健康?告诉你
2024-25赛季德甲第12轮积分榜:拜仁领跑,中游球队竞争激烈
老人牙齿全部掉光怎么办?全口义齿 vs 种植修复,哪种更适合?
亮“舰”!一起来看“福建籍”舰队
重庆楼市大动作!取消限售第一天情况如何?
中老年人冬季养生必吃的四种“富贵菜”,搭配详细烹饪指南