装饰模式解析:基本概念和实例教程
创作时间:
作者:
@小白创作中心
装饰模式解析:基本概念和实例教程
引用
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;
}
}
}
热门推荐
30分钟"爆破"癌细胞!日本BNCT(硼中子俘获疗法)正式开放海外患者诊疗
高考后是否应该立即报考驾照?一个真实案例引发的思考
生活中总会有不如意,学会接受,不必强求,心态放平,才能快乐
没有“边界感”的中式社交,被年轻人疯狂吐槽
脑溢血与脑梗:一文读懂两者核心差异
脑溢血与脑梗:一文读懂两者核心差异
脑溢血与脑梗:一文读懂两者核心差异
降血糖食物怎么选最好?9大降血糖食物表和早餐菜单推荐
马齿苋:能预防湿疹的野菜,维生素C含量是西梅的16倍!夏季要多吃
漫步三坊七巷:一场时光之旅,感受林则徐的英雄气概
三坊七巷:千年古街的传承与创新
山东传媒职业学院:新媒体技术的未来之星
泡澡听音乐,双倍解压神器!
山东传媒职业学院:双师型教师培养的创新实践
山东传媒职业学院影视专业:培养影视行业专业人才的摇篮
山东传媒职业学院:就业前景十佳院校!
山东传媒职业学院:播音主持专业培养目标揭秘
嫦娥四号核电池揭秘:中国在这一领域已实现突破
2025香港端午节:龙舟竞渡,美食荟萃
端午节龙舟美食会的历史渊源揭秘
广西荔浦:书写衣架之都传奇 锚定新兴产业赛道
千年古邑 活力荔浦
视网膜脱离≠立即失明 重庆普瑞眼科:需要警惕4个征兆
63岁费翔不老神话:40年运动自律成就逆天身材
VR技术让土家族文化“活”起来
黄渤谈《封神第二部》:骑马戏“其实挺危险的”
《封神第二部》口碑票房双扑,中国电影产业面临深度思考
射手集体加强后,为啥鲁班七号好像还变弱了?打肉慢只是原因之一
利巴韦林的作用与功效
家庭亲子时光:一起玩转2024最新海龟汤游戏