装饰模式解析:基本概念和实例教程
创作时间:
作者:
@小白创作中心
装饰模式解析:基本概念和实例教程
引用
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;
}
}
}
热门推荐
【JAMA】重磅综述:原发性血小板增多症
紫微命盘反推八字:紫微斗数与八字命理的神秘联系
山海连城绿美深圳不断“上新”
国产MPV崛起下的埃尔法“神话”:市场逻辑与消费心理的深度剖析
深观察|新质生产力,会给大学生的就业带来怎样影响?
让收音机再陪陪老人
小型私人影院设计中的装修与声学处理关键剖析
古代饮酒哲学:酒无量、不及乱
新老客户平衡管理有难题?掌握方法实现客户管理协调发展
随着 AI 绘画和 GPT 技术的不断突破,图像编辑未来的交互形式是怎样的?
左手小拇指疼痛怎么办?多种原因及处理方法详解
16种MBTI人格分别代表了什么意思?看这一篇就够了!
了解嘌呤:对健康的影响与摄入控制
京杭大运河:浩大工程,流淌千年的科技智慧
平面设计在日常生活中的重要性与影响力分析
卖房如何提升看房体验?
三元锂VS磷酸铁锂:一字之差,新能源汽车电池如何选?
雨水养生正当时!中医教你三招,助您远离春困湿重
电影《敦刻尔克》中,如何营造战争紧张刺激的场面气氛?
三元锂VS磷酸铁锂:一字之差,新能源汽车电池如何选?
古风古韵,古典时期阿尔戈斯如何进行外交的?
加拿大留学移民新政策解析:2024年最新变化与移民挑战
瓜蒌:清热化痰、宽胸散结的中药材
如何了解企业搬迁的原因和影响?这种搬迁如何适应市场变化?
学生意外险报销都要什么手续
右手无名指关节痛的可能原因和治疗方法
脑供血不足,别怕!这几招改善动作请收好
Win11更新后电脑很卡很慢的解决方案
体检有“缺血灶”是大脑缺血了?有“腔梗灶”是得了脑梗死?|世界卒中日
中国新能源汽车动力系统:崛起之路与未来技术趋势探秘