装饰器模式
本课属于 Coddy Dart 学习旅程的“面向对象编程”单元。第 96 课,共 110 课。
装饰器模式让你可以通过用称为装饰器的特殊对象包装对象,动态地为对象添加新行为。与在编译时添加行为的继承不同,装饰器可以在运行时附加额外的职责,而无需修改原始类。
关键在于,原始对象和装饰器都实现了相同的接口。
装饰器包装原始对象,将操作委托给它,并在之前或之后添加自己的行为:
abstract class Coffee {
String getDescription();
double getCost();
}
class SimpleCoffee implements Coffee {
@override
String getDescription() => 'Simple Coffee';
@override
double getCost() => 2.0;
}
class MilkDecorator implements Coffee {
final Coffee _coffee;
MilkDecorator(this._coffee);
@override
String getDescription() => '${_coffee.getDescription()}, Milk';
@override
double getCost() => _coffee.getCost() + 0.5;
}
class SugarDecorator implements Coffee {
final Coffee _coffee;
SugarDecorator(this._coffee);
@override
String getDescription() => '${_coffee.getDescription()}, Sugar';
@override
double getCost() => _coffee.getCost() + 0.2;
}
void main() {
Coffee coffee = SimpleCoffee();
coffee = MilkDecorator(coffee);
coffee = SugarDecorator(coffee);
print(coffee.getDescription()); // 普通咖啡、牛奶、糖
print(coffee.getCost()); // 2.7
}每个装饰器都会包装前一个对象并增强它。你可以按任意组合叠加多个装饰器,无需为每种可能的组合都创建一个子类,就能实现灵活的行为。当你需要为对象添加功能,同时不影响同类的其他对象时,这种模式非常适用。
挑战
简单让我们使用装饰器模式来构建一个披萨点单系统!你将创建一个基础披萨,并用各种配料对它进行扩展。每种配料都会包装前一个对象,并增加描述内容和价格。
你将把代码分成两个文件:
pizza.dart:这个文件包含披萨接口和所有装饰器类。先创建一个抽象类Pizza,定义两个方法:String getDescription()和double getPrice()。然后创建一个实现Pizza的PlainPizza类,它的描述是Plain Pizza,价格为8.0。接着创建三个装饰器类,每个类都会包装一个Pizza并对它进行扩展:CheeseDecorator:在描述中添加, Cheese,并在价格上增加1.5PepperoniDecorator:在描述中添加, Pepperoni,并在价格上增加2.0MushroomDecorator:在描述中添加, Mushrooms,并在价格上增加1.25
Pizza,在构造函数中接收一个Pizza,并先委托给被包装的披萨,再添加自己的内容。main.dart:导入披萨文件,演示如何叠加装饰器来构建定制订单。先创建一个PlainPizza,然后依次用CheeseDecorator、PepperoniDecorator和MushroomDecorator进行包装。打印最终披萨的描述,然后打印Total: $,后面跟上价格。
注意每个装饰器都是在前一个装饰器的基础上进行扩展的。通过叠加职责单一的装饰器,你就能创建一个配料丰富的披萨!
预期输出:
Plain Pizza, Cheese, Pepperoni, Mushrooms
Total: $12.75亲手试试
import 'pizza.dart';
void main() {
// TODO:创建一个 PlainPizza 对象
// TODO:用 CheeseDecorator 包装它
// TODO:再用 PepperoniDecorator 包装它
// TODO:最后用 MushroomDecorator 包装整个披萨
// TODO:打印最终披萨的描述
// TODO:打印 "Total: $",后面接价格
}
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: Dart 在线编译器