装饰模式解析:基本概念和实例教程
创作时间:
作者:
@小白创作中心
装饰模式解析:基本概念和实例教程
引用
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;
}
}
}
热门推荐
蜂蜜可以带上飞机吗?高铁、火车、地铁呢?
腰椎间盘突出吃什么食物有帮助
预防胆结石的运动指南:医生的专业建议
59式坦克全面退役:解放军陆军坦克发展新阶段
一周一日三餐的营养搭配表简单
小红书开店必读:如何精准定位吸引目标客户?
主观客观构成要件:法律事实认定的核心要素
萧伯纳:戏剧界的激情先驱与社会观察家
道教信仰中的神仙世界及其文化意义
6J23精密合金的退火工艺:性能优化与应用前景
3线油门踏板接线图怎样看好坏
鞋子大了怎么办?实用的鞋垫解决方案
以“新”铸型 电力未来正来
蜜蜂与苍蝇:从外形特征看两种常见昆虫的区别
津液不足的症状及改善方法
信用卡:一把金融双刃剑,是福还是祸?
论人体气血运行规律——以杜金龙先生的观点为例
车辆突然断电该如何应对?这种情况可能由哪些原因引起?
汽车电池检查与保养全攻略
蒙古包,动静相宜有乾坤
深入解析:伤官大运遇到各种流年的影响
辽宁舰携歼-35返港:战力提升五倍,从训练舰到战斗舰的蜕变
如何解决FPS低的问题?代码优化方法有哪些?
中央空调耗电量与使用技巧解析
阿伦特丨平庸之恶,离你很近
频繁眩晕别忽视!可能是听力在“捣鬼”
耳鸣头晕是为什么
如何与冠心病和平相处?
没有按时吃药或者忘记吃的药,到底要不要补上?
口腔真菌感染是什么症状