【声明】本题目来源于卡码网(题目页面 (kamacoder.com))
【提示:如果不想看文字介绍,可以直接跳转到C++编码部分】
【简介】什么是装饰模式
????????通常情况下,扩展类的功能可以通过继承实现,但是扩展越多,?类越多,装饰模式( Decorator Pattern , 结构型设计模式)可以在不定义?类的情况下动态的给对象添加?些额外的功能。具体的做法是将原始对象放?包含?为的特殊封装类(装饰类),从?为原始对象动态添加新的?为,??需修改其代码。
????????举个简单的例?,假设你有?个基础的图形类,你想要为图形类添加颜?、边框、阴影等功能,如果每个功能都实现?个?类,就会导致产??量的类,这时就可以考虑使?装饰模式来动态地添加,?不需要修改图形类本身的代码,这样可以使得代码更加灵活、更容易维护和扩展。
【基本结构】
????????装饰模式包含以下四个主要??:
【基本实现】
装饰模式的实现包括以下步骤:(以Java代码做示例)
1. 定义Component接?
// 组件接?
public interface Component {
void operation();
}
2. 实现 ConcreteComponent
// 具体组件
public class ConcreteComponent implements Component {
@Override
public void operation() {
System.out.println("ConcreteComponent operation");
}
}
3.?定义Decorator装饰类,继承?Component
// 定义?个抽象的装饰者类,继承?Component
public abstract class Decorator implements Component {
protected Component component;
public Decorator(Component component) {
this.component = component;
}
@Override
public void operation() {
component.operation();
}
}
4.?定义具体的装饰者实现,给具体组件对象添加功能。
// 具体的装饰者实现
public class ConcreteDecorator extends Decorator {
public ConcreteDecorator(Component component) {
super(component);
}
// 根据需要添加额外的?法
@Override
public void operation() {
// 可以在调?前后添加额外的?为
System.out.println("Before operation in ConcreteDecorator");
super.operation();
System.out.println("After operation in ConcreteDecorator");
}
}
5.?在客户端使?
public class Main {
public static void main(String[] args) {
// 创建具体组件
Component concreteComponent = new ConcreteComponent();
// 使?具体装饰者包装具体组件
Decorator decorator = new ConcreteDecorator(concreteComponent);
// 调?操作
decorator.operation();
}
}
【应用场景】
????????装饰模式通常在以下?种情况使?:
????????在Java的I/O库中,装饰者模式被?泛?于增强I/O流的功能。例如, BufferedInputStream 和
BufferedOutputStream 这两个类提供了缓冲区的?持,通过在底层的输?流和输出流上添加缓冲区,提?了读写的效率,它们都是InputStream 和OutputStream 的装饰器。BufferedReader 和BufferedWriter 这两个类与BufferedInputStream 和BufferedOutputStream 类似,提供了字符流的缓冲功能,是Reader和Writer的装饰者。
【编码部分】
1. 题目描述
????????小明喜欢品尝不同口味的咖啡,他发现每种咖啡都可以加入不同的调料,比如牛奶、糖和巧克力。他决定使用装饰者模式制作自己喜欢的咖啡。?
????????请设计一个简单的咖啡制作系统,使用装饰者模式为咖啡添加不同的调料。系统支持两种咖啡类型:黑咖啡(Black Coffee)和拿铁(Latte)。
2. 输入描述
????????多行输入,每行包含两个数字。第一个数字表示咖啡的选择(1 表示黑咖啡,2 表示拿铁),第二个数字表示要添加的调料类型(1 表示牛奶,2 表示糖)。
3. 输出描述
????????根据每行输入,输出制作咖啡的过程,包括咖啡类型和添加的调料。
4. C++编码实例
/**
* @version Copyright (c) 2024 NCDC, Servo。 Unpublished - All rights reserved
* @file DecoratorMode.hpp
* @brief 装饰模式
* @autor 写代码的小恐龙er
* @date 2024/01/11
*/
#include <iostream>
#include <string>
using namespace std;
// 前置声明
// 抽象的基类 -- 接口类
class Coffee;
// 具体的黑咖啡类
class BlackCoffee;
// 具体的拿铁类
class Latte;
// 装饰者抽象类 -- 接口类的派生类
class Decorator;
// 具体的牛奶装饰类 -- Decorator的派生类
class MilkDecorator;
// 具体的糖装饰类 -- Decorator的派生类
class SugarDecorator;
// 抽象的基类 -- 接口类
class Coffee
{
public:
virtual void PrintInfo() = 0;
};
// 具体的黑咖啡类
class BlackCoffee : public Coffee
{
public:
// 重载接口函数
void PrintInfo() override
{
std::cout << "Brewing Black Coffee" << endl;
}
};
// 具体的拿铁类
class Latte : public Coffee
{
public:
// 重载接口函数
void PrintInfo() override
{
std::cout << "Brewing Latte" << endl;
}
};
// 装饰者抽象类 -- 接口类的派生类
class Decorator : public Coffee
{
protected:
// 持有一个抽象接口类的对象
Coffee *_coffee;
public:
// 构造函数重载
// 当派生类重载了构造函数时 基类需要定义默认构造函数
Decorator(){}
Decorator(Coffee *coffee){
this->_coffee = coffee;
}
// 重载抽象类的接口函数
void PrintInfo() override {
_coffee->PrintInfo();
}
};
// 具体的牛奶装饰类 -- Decorator的派生类
class MilkDecorator: public Decorator
{
public:
// 持有一个装饰类的对象
Decorator *_decorator;
public:
// 构造函数重载
MilkDecorator(Decorator *decorator){
this->_decorator = decorator;
}
// 重载抽象类的接口函数
void PrintInfo() override {
_decorator->PrintInfo();
std::cout << "Adding Milk" << endl;
}
};
// 具体的糖装饰类 -- Decorator的派生类
class SugarDecorator : public Decorator
{
public:
// 持有一个装饰类的对象
Decorator *_decorator;
public:
// 构造函数重载
SugarDecorator(Decorator *decorator){
this->_decorator = decorator;
}
// 重载抽象类的接口函数
void PrintInfo() override {
_decorator->PrintInfo();
std::cout << "Adding Sugar" << endl;
}
};
int main()
{
// 咖啡类型
int coffeeType = 0;
// 调料类型
int seasoningType = 0;
while(std::cin >> coffeeType >> seasoningType)
{
Coffee *coffee = nullptr;
// 咖啡类型
if(coffeeType == 1){
coffee = new BlackCoffee();
}
else if (coffeeType == 2){
coffee = new Latte();
}
else return 0;
Decorator *decorator = new Decorator(coffee);
// 调料类型
if(seasoningType == 1){
coffee = new MilkDecorator(decorator);
}
else if (seasoningType == 2){
coffee = new SugarDecorator(decorator);
}
else return 0;
// 输出制作过程
coffee->PrintInfo();
delete decorator;
decorator = nullptr;
delete coffee;
coffee = nullptr;
}
return 0;
}
......
To be continued.