范围\目的 | 创建型模式 | 结构型模式 | 行为型模式 |
---|---|---|---|
类模式 | 工厂方法 | (类)适配器 | 模板方法、解释器 |
对象模式 | 单例原型抽象工厂建造者 | 代理装饰桥接(对象)适配器外观享元组合 | 策略职责链状态观察者中介者迭代器访问者备忘录命令 |
总结一下,区别在于:
行为模型可以通过各种图形表示,如STD-状态转换图、活动图、状态机图等。
定义一个操作的算法骨架,允许子类重新定义某些步骤而不改变算法的结构。
在抽象类中公开定义了执行的方法,子类可以按需重写其方法,但是要以抽象类中定义的方式调用方法。总结起来就是:定义一个操作的算法结构,而将一些步骤延迟到子类中。在不改变算法结构的情况下,子类能重定义该算法的特定步骤。
无论造型如何变化,不变的有两种东西:“奶油”和“面包”。其余的材料随意搭配,就凑成了各式各样的蛋糕。
模板方法模式其实是一个比较简单的设计模式,它有如下优点:
更详细的了解,推荐阅读:
下面是模板方法模式
// 抽象类
class Cake {
// 模板方法,定义了做蛋糕的步骤
makeCake() {
this.prepareIngredients();
this.bake();
this.decorate();
}
// 以下方法由子类实现
prepareIngredients() {
throw new Error("prepareIngredients() must be overridden");
}
bake() {
console.log("Baking the cake. Be patient.");
}
decorate() {
throw new Error("decorate() must be overridden");
}
}
// 具体类 - 草莓蛋糕
class StrawberryCake extends Cake {
prepareIngredients() {
console.log("Gathering ingredients for a Strawberry Cake.");
}
decorate() {
console.log("Decorating the cake with strawberries.");
}
}
// 具体类 - 芒果蛋糕
class MangoCake extends Cake {
prepareIngredients() {
console.log("Gathering ingredients for a Mango Cake.");
}
decorate() {
console.log("Decorating the cake with mango slices.");
}
}
// 使用模板方法
const strawberryCake = new StrawberryCake();
strawberryCake.makeCake();
const mangoCake = new MangoCake();
mangoCake.makeCake();
接下来,我们来实现抽象工厂模式的例子。我们将创建一个抽象工厂 CakeFactory,它定义了创建蛋糕和装饰品的接口。然后,我们将创建两个具体的工厂 StrawberryCakeFactory 和 MangoCakeFactory,它们分别实现了 CakeFactory 类中定义的方法。
// 抽象工厂
class CakeFactory {
createCake() {
throw new Error("createCake() must be overridden");
}
createDecoration() {
throw new Error("createDecoration() must be overridden");
}
}
// 具体工厂 - 草莓蛋糕工厂
class StrawberryCakeFactory extends CakeFactory {
createCake() {
return new StrawberryCake();
}
createDecoration() {
return "Strawberries";
}
}
// 具体工厂 - 芒果蛋糕工厂
class MangoCakeFactory extends CakeFactory {
createCake() {
return new MangoCake();
}
createDecoration() {
return "Mango slices";
}
}
// 客户端代码
function makeCake(factory) {
const cake = factory.createCake();
const decoration = factory.createDecoration();
cake.makeCake();
console.log(`Decorating with: ${decoration}`);
}
// 使用抽象工厂
const strawberryFactory = new StrawberryCakeFactory();
makeCake(strawberryFactory);
const mangoFactory = new MangoCakeFactory();
makeCake(mangoFactory);
上面两段代码展示了模板方法模式和抽象工厂模式的不同应用场景和核心点。让我们来分析它们的主要差异:
模板方法模式的核心点:
抽象工厂模式的核心点:
定义一系列算法,并使它们可以互换——该模式定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户,即:策略模式允许算法独立于使用它们的客户端而变化。
策略模式属于对象行为模式,它通过对算法进行封装,把使用算法的责任和算法的实现分割开来,并委派给不同的对象对这些算法进行管理。
策略模式的主要角色如下:
策略模式代码示例:
// 策略对象定义不同的验证算法
const validationStrategies = {
isNonEmpty: {
validate: (value) => value !== '',
message: 'The value cannot be empty'
},
isNumber: {
validate: (value) => !isNaN(parseFloat(value)) && isFinite(value),
message: 'The value must be a number'
},
isEmail: {
validate: (value) => /\S+@\S+\.\S+/.test(value),
message: 'The value must be an email address'
}
};
// Context 类,使用策略对象的 validate 方法
class Validator {
constructor() {
this.errors = [];
this.validationStrategies = {};
}
// 添加验证规则
addValidation(field, strategy) {
this.validationStrategies[field] = strategy;
}
// 执行验证
validate(data) {
this.errors = [];
for (const field in this.validationStrategies) {
const strategy = this.validationStrategies[field];
if (!strategy.validate(data[field])) {
this.errors.push({ field: field, error: strategy.message });
}
}
return this.errors.length === 0;
}
// 获取验证错误信息
getErrors() {
return this.errors;
}
}
// 使用策略模式的客户端代码
const validator = new Validator();
validator.addValidation('username', validationStrategies.isNonEmpty);
validator.addValidation('age', validationStrategies.isNumber);
validator.addValidation('email', validationStrategies.isEmail);
const data = {
username: 'JohnDoe',
age: '30',
email: 'johndoe@example.com'
};
const isValid = validator.validate(data);
if (isValid) {
console.log('Validation passed');
} else {
console.error('Validation failed:', validator.getErrors());
}
下面的代码改为typescript(纯种的策略模式结构)
// 抽象策略(Strategy)接口
interface ValidationStrategy {
validate(value: string): boolean;
errorMessage: string;
}
// 具体策略(Concrete Strategy)类 - 非空验证
class NonEmptyValidation implements ValidationStrategy {
errorMessage = 'The value cannot be empty';
validate(value: string): boolean {
return value !== '';
}
}
// 具体策略(Concrete Strategy)类 - 数字验证
class NumberValidation implements ValidationStrategy {
errorMessage = 'The value must be a number';
validate(value: string): boolean {
return !isNaN(parseFloat(value)) && isFinite(value as any);
}
}
// 具体策略(Concrete Strategy)类 - 邮箱验证
class EmailValidation implements ValidationStrategy {
errorMessage = 'The value must be an email address';
validate(value: string): boolean {
return /\S+@\S+\.\S+/.test(value);
}
}
// 环境(Context)类
class Validator {
private errors: string[] = [];
private validationStrategies: Map<string, ValidationStrategy> = new Map();
// 添加验证规则
addValidation(field: string, strategy: ValidationStrategy): void {
this.validationStrategies.set(field, strategy);
}
// 执行验证
validate(data: { [key: string]: string }): boolean {
this.errors = [];
for (const [field, strategy] of this.validationStrategies) {
if (!strategy.validate(data[field])) {
this.errors.push(`${field}: ${strategy.errorMessage}`);
}
}
return this.errors.length === 0;
}
// 获取验证错误信息
getErrors(): string[] {
return this.errors;
}
}
// 客户端代码
const validator = new Validator();
validator.addValidation('username', new NonEmptyValidation());
validator.addValidation('age', new NumberValidation());
validator.addValidation('email', new EmailValidation());
const data = {
username: 'JohnDoe',
age: '30',
email: 'johndoe@example.com'
};
const isValid = validator.validate(data);
if (isValid) {
console.log('Validation passed');
} else {
console.error('Validation failed:', validator.getErrors());
}
具体推荐阅读
设计模式(十八)----行为型模式之策略模式 https://www.cnblogs.com/xiaoyh/p/16560074.html
定义对象之间的一对多依赖关系,以便当一个对象的状态发生改变时,所有依赖它的对象都会得到通知并自动更新。
当需要松散耦合对象并允许它们在不了解彼此的情况下进行通信时。例如,
具体推荐阅读
提供一种方法来顺序访问集合中的元素,而不暴露集合的底层表示。
典型场景:
当需要遍历集合中的元素,但又不想直接访问集合的内部结构时。例如
迭代器模式主要包含以下角色:
迭代器的代码实现:
// 定义一个迭代器接口
interface Iterator<T> {
hasNext(): boolean;
next(): T;
}
// 定义一个具体迭代器
class ConcreteIterator<T> implements Iterator<T> {
private collection: T[];
private index: number = 0;
constructor(collection: T[]) {
this.collection = collection;
}
hasNext(): boolean {
return this.index < this.collection.length;
}
next(): T {
return this.collection[this.index++];
}
}
// 定义一个聚合接口
interface Aggregate<T> {
createIterator(): Iterator<T>;
}
// 定义一个具体聚合
class ConcreteAggregate<T> implements Aggregate<T> {
private collection: T[];
constructor(collection: T[]) {
this.collection = collection;
}
createIterator(): Iterator<T> {
return new ConcreteIterator(this.collection);
}
}
// 使用迭代器模式
const aggregate = new ConcreteAggregate([1, 2, 3, 4, 5]);
const iterator = aggregate.createIterator();
while (iterator.hasNext()) {
console.log(iterator.next());
}
具体参看:
设计模式(二十四)----行为型模式之迭代器模式 https://www.cnblogs.com/xiaoyh/p/16563331.html
将请求链式传递给一系列处理程序,直到有一个处理程序处理该请求。
当需要将请求处理委托给多个对象,并且处理顺序不重要时。例如
typescript 代码实现:
// 抽象处理者
abstract class Approver {
protected successor: Approver | null = null;
// 设置下一个处理者
public setSuccessor(successor: Approver): void {
this.successor = successor;
}
// 处理请求的方法,由子类实现
public abstract handleRequest(leaveDays: number): void;
}
// 具体处理者 - 组织领导
class TeamLeader extends Approver {
public handleRequest(leaveDays: number): void {
if (leaveDays <= 2) {
console.log(`TeamLeader approved ${leaveDays} day(s) leave.`);
} else if (this.successor) {
this.successor.handleRequest(leaveDays);
}
}
}
// 具体处理者 - 部门领导
class DepartmentManager extends Approver {
public handleRequest(leaveDays: number): void {
if (leaveDays <= 5) {
console.log(`DepartmentManager approved ${leaveDays} day(s) leave.`);
} else if (this.successor) {
this.successor.handleRequest(leaveDays);
}
}
}
// 具体处理者 - 总经理
class GeneralManager extends Approver {
public handleRequest(leaveDays: number): void {
if (leaveDays <= 10) {
console.log(`GeneralManager approved ${leaveDays} day(s) leave.`);
} else {
console.log(`Leave request for ${leaveDays} day(s) requires an executive meeting.`);
}
}
}
// 客户端代码
const teamLeader = new TeamLeader();
const departmentManager = new DepartmentManager();
const generalManager = new GeneralManager();
// 设置责任链
teamLeader.setSuccessor(departmentManager);
departmentManager.setSuccessor(generalManager);
// 发起请假请求
teamLeader.handleRequest(2); // TeamLeader can handle this request
teamLeader.handleRequest(4); // DepartmentManager has to handle this request
teamLeader.handleRequest(8); // GeneralManager has to handle this request
teamLeader.handleRequest(12); // Needs executive meeting
之前我觉得洋葱模型就是挺适合责任链模式的,,其是不是的!。
具体参看:
定义一个对象,它封装了多个对象之间的交互。中介者模式使对象之间松散耦合,并允许它们独立于彼此进行通信。
又叫调停模式,定义一个中介角色来封装一系列对象之间的交互,使原有对象之间的耦合松散,且可以独立地改变它们之间的交互。
如果一个系统中对象之间的联系呈现出网状结构,对象之间存在大量多对多关系,将导致关系及其复杂,这些对象称为 "同事对象"。我们可以引入一个中介者对象,使各个同事对象只跟中介者对象打交道,将同事对象之间的关系行为进行分离和封装,使之成为一个松耦合的系统。
解耦各个同事对象之间的交互关系。每个对象都持有中介者对象的引用,只跟中介者对象打交道。通过中介者对象统一管理这些交互关系,并且还可以在同事对象的逻辑上封装自己的逻辑。
当需要控制多个对象之间的复杂交互时。例如
中介者模式包含以下主要角色:
// 中介者接口
interface Mediator {
notify(sender: object, event: string): void;
}
// 具体中介者
class ConcreteMediator implements Mediator {
private component1: Component1;
private component2: Component2;
constructor(c1: Component1, c2: Component2) {
this.component1 = c1;
this.component1.setMediator(this);
this.component2 = c2;
this.component2.setMediator(this);
}
public notify(sender: object, event: string): void {
if (event === 'A') {
console.log('Mediator reacts on A and triggers following operations:');
this.component2.doC();
} else if (event === 'D') {
console.log('Mediator reacts on D and triggers following operations:');
this.component1.doB();
this.component2.doC();
}
}
}
// 基础组件
class BaseComponent {
protected mediator: Mediator;
constructor(mediator?: Mediator) {
this.mediator = mediator!;
}
public setMediator(mediator: Mediator): void {
this.mediator = mediator;
}
}
// 具体组件1
class Component1 extends BaseComponent {
public doA(): void {
console.log('Component 1 does A.');
this.mediator.notify(this, 'A');
}
public doB(): void {
console.log('Component 1 does B.');
this.mediator.notify(this, 'B');
}
}
// 具体组件2
class Component2 extends BaseComponent {
public doC(): void {
console.log('Component 2 does C.');
this.mediator.notify(this, 'C');
}
public doD(): void {
console.log('Component 2 does D.');
this.mediator.notify(this, 'D');
}
}
// 客户端代码
const c1 = new Component1();
const c2 = new Component2();
const mediator = new ConcreteMediator(c1, c2);
console.log('Client triggers operation A.');
c1.doA();
console.log('Client triggers operation D.');
c2.doD();
在这个示例中,ConcreteMediator 类通过实现 Mediator 接口充当中介者。Component1 和 Component2 是两个基于 BaseComponent 的具体组件,它们通过中介者进行通信,而不是直接相互调用。当一个组件改变状态或需要与其他组件通信时,它会通过中介者来协调这些交互。
中介者模式适用于需要降低多个组件或服务之间复杂交云的情况,它有助于将系统的通信复杂性集中管理,从而使系统更加模块化和易于维护。
具体参看文章:
设计模式(二十三)----行为型模式之中介者模式 https://www.cnblogs.com/xiaoyh/p/16563324.html
将操作与对象结构分离,以便可以在不改变结构的情况下向对象添加新操作。
访问者模式能将算法与其所作用的对象隔离开来。
当需要在不修改对象结构的情况下向对象添加新操作时。例如,
typescript代码的简单实现
/// 访问者接口
interface Visitor {
visitConcreteElementA(element: ConcreteElementA): void;
visitConcreteElementB(element: ConcreteElementB): void;
}
// 具体访问者
class ConcreteVisitor1 implements Visitor {
public visitConcreteElementA(element: ConcreteElementA): void {
console.log(`ConcreteVisitor1: Visiting ${element.operationA()}`);
}
public visitConcreteElementB(element: ConcreteElementB): void {
console.log(`ConcreteVisitor1: Visiting ${element.operationB()}`);
}
}
// 另一个具体访问者
class ConcreteVisitor2 implements Visitor {
public visitConcreteElementA(element: ConcreteElementA): void {
console.log(`ConcreteVisitor2: Visiting ${element.operationA()}`);
}
public visitConcreteElementB(element: ConcreteElementB): void {
console.log(`ConcreteVisitor2: Visiting ${element.operationB()}`);
}
}
// 元素接口
interface Element {
accept(visitor: Visitor): void;
}
// 具体元素A
class ConcreteElementA implements Element {
public accept(visitor: Visitor): void {
visitor.visitConcreteElementA(this);
}
public operationA(): string {
return 'ConcreteElementA';
}
}
// 具体元素B
class ConcreteElementB implements Element {
public accept(visitor: Visitor): void {
visitor.visitConcreteElementB(this);
}
public operationB(): string {
return 'ConcreteElementB';
}
}
// 客户端代码
const elements: Element[] = [
new ConcreteElementA(),
new ConcreteElementB(),
];
const visitor1: Visitor = new ConcreteVisitor1();
const visitor2: Visitor = new ConcreteVisitor2();
elements.forEach((element) => {
element.accept(visitor1);
element.accept(visitor2);
});
具体的例子:
// 访问者接口
interface ComputerPartVisitor {
visitKeyboard(keyboard: Keyboard): void;
visitMouse(mouse: Mouse): void;
visitMonitor(monitor: Monitor): void;
}
// 计算机外设接口
interface ComputerPart {
accept(visitor: ComputerPartVisitor): void;
}
// 键盘类
class Keyboard implements ComputerPart {
public accept(visitor: ComputerPartVisitor): void {
visitor.visitKeyboard(this);
}
public type(): void {
console.log('Keyboard typing...');
}
}
// 鼠标类
class Mouse implements ComputerPart {
public accept(visitor: ComputerPartVisitor): void {
visitor.visitMouse(this);
}
public click(): void {
console.log('Mouse clicking...');
}
}
// 显示器类
class Monitor implements ComputerPart {
public accept(visitor: ComputerPartVisitor): void {
visitor.visitMonitor(this);
}
public display(): void {
console.log('Monitor displaying...');
}
}
// 通用计算机外设访问者
class GeneralComputerPartVisitor implements ComputerPartVisitor {
public visitKeyboard(keyboard: Keyboard): void {
keyboard.type();
}
public visitMouse(mouse: Mouse): void {
mouse.click();
}
public visitMonitor(monitor: Monitor): void {
monitor.display();
}
}
// 显示器访问者
class MonitorVisitor implements ComputerPartVisitor {
public visitKeyboard(keyboard: Keyboard): void {
// 不关心键盘
}
public visitMouse(mouse: Mouse): void {
// 不关心鼠标
}
public visitMonitor(monitor: Monitor): void {
console.log('Applying special monitor calibration...');
monitor.display();
}
}
// 客户端代码
const parts: ComputerPart[] = [
new Keyboard(),
new Mouse(),
new Monitor(),
];
const generalVisitor: ComputerPartVisitor = new GeneralComputerPartVisitor();
const monitorVisitor: ComputerPartVisitor = new MonitorVisitor();
parts.forEach((part) => {
part.accept(generalVisitor); // 应用通用访问者
part.accept(monitorVisitor); // 应用显示器访问者
});
在这个示例中,ComputerPartVisitor 接口定义了访问者需要实现的方法,GeneralComputerPartVisitor 是一个通用的访问者,它对所有外设执行操作。MonitorVisitor 是一个专门为显示器设计的访问者,它只对显示器执行特殊的操作。
ComputerPart 接口定义了一个 accept 方法,Keyboard、Mouse 和 Monitor 是实现了该接口的具体外设类。每个外设类都实现了 accept 方法,该方法接受一个访问者并调用其访问方法。
具体参看:
定义一个语言的文法,并提供一个解释器来解释该语言中的句子。
当需要解释一个特定领域的语言时。例如,
typescript实现
// 表达式接口
interface Expression {
interpret(): number;
}
// 数字表达式
class NumberExpression implements Expression {
private value: number;
constructor(value: number) {
this.value = value;
}
public interpret(): number {
return this.value;
}
}
// 加法表达式
class AddExpression implements Expression {
private leftExpression: Expression;
private rightExpression: Expression;
constructor(left: Expression, right: Expression) {
this.leftExpression = left;
this.rightExpression = right;
}
public interpret(): number {
return this.leftExpression.interpret() + this.rightExpression.interpret();
}
}
// 减法表达式
class SubtractExpression implements Expression {
private leftExpression: Expression;
private rightExpression: Expression;
constructor(left: Expression, right: Expression) {
this.leftExpression = left;
this.rightExpression = right;
}
public interpret(): number {
return this.leftExpression.interpret() - this.rightExpression.interpret();
}
}
// 客户端代码
const expression: Expression = new AddExpression(
new NumberExpression(5),
new SubtractExpression(
new NumberExpression(10),
new NumberExpression(3)
)
);
console.log(expression.interpret()); // 输出结果应该是 5 + (10 - 3) = 12
允许对象在内部状态改变时改变其行为。
状态模式与有限状态机的概念紧密相关。
当对象的内部状态会影响其行为时。例如,
状态模式包含以下主要角色。
typescript 代码实现:
// 状态接口
interface State {
handle(context: Context): void;
}
// 具体状态A
class ConcreteStateA implements State {
public handle(context: Context): void {
console.log('Handling state A.');
context.setState(new ConcreteStateB());
}
}
// 具体状态B
class ConcreteStateB implements State {
public handle(context: Context): void {
console.log('Handling state B.');
context.setState(new ConcreteStateA());
}
}
// 上下文类
class Context {
private state: State;
constructor(state: State) {
this.state = state;
}
public setState(state: State): void {
this.state = state;
}
public request(): void {
this.state.handle(this);
}
}
// 客户端代码
const context = new Context(new ConcreteStateA());
context.request(); // Handling state A.
context.request(); // Handling state B.
context.request(); // Handling state A.
在前端开发中,状态模式可以用于管理组件或应用的状态。例如,Redux库就是一个状态管理库,它在某种程度上体现了状态模式的思想。在Redux中,状态转换逻辑通过纯函数(reducers)来管理,每个reducer根据当前状态和传入的action来计算新状态。
// Redux中的reducer示例
function visibilityFilter(state = 'SHOW_ALL', action) {
switch (action.type) {
case 'SET_VISIBILITY_FILTER':
return action.filter;
default:
return state;
}
}
在这个例子中,visibilityFilter 函数是一个reducer,它根据当前状态和action来返回新状态,这与状态模式中的状态转换逻辑类似。
推荐本站的:《状态机图教程 (UML State Diagram) 》、《从有限状态机、图灵机到现代计算机——排版整理笔记版》、《React 源码剖析系列—生命周期的管理艺术—有限状态机》
状态模式和策略模式都可以避免多重条件选择语句,它们的类图也十分相似,它们都有一个上下文(Context)、一些策略类(Strategy)或者状态类(State),上下文把请求委托给这些类来执行。
如果只是单纯的多情况if else ,各个条件之间是平等又平行的,没有任何联系,就可以选择使用策略模式,代码可能会更优雅易维护,成本会低一些,策略模式要求了解策略类中的算法逻辑,以便它们之间的互相替换;状态模式中,状态和状态对应的行为以及状态间的切换是早就规定好的,都是在内部发生的,不需要了解具体的细节,类似IM socket的场景,状态机会更加优雅。
具体参看:
如果只是单纯的多情况if else ,各个条件之间是平等又平行的,没有任何联系,就可以选择使用策略模式,代码可能会更优雅易维护,成本会低一些,策略模式要求了解策略类中的算法逻辑,以便它们之间的互相替换;状态模式中,状态和状态对应的行为以及状态间的切换是早就规定好的,都是在内部发生的,不需要了解具体的细节,类似IM socket的场景,状态机会更加优雅。
捕获一个对象的内部状态,以便以后可以恢复该状态。
当需要保存和恢复对象的内部状态时。例如,
理解备忘录模式并不难,但关键在于如何设计备忘录类和负责人类。由于在备忘录中存储的是原发器的中间状态,因此需要防止原发器以外的其他对象访问备忘录,特别是不允许其他对象来修改备忘录。
typescript代码实现
// 备忘录类
class ChessMemento {
private state: string;
constructor(state: string) {
this.state = state;
}
public getState(): string {
return this.state;
}
}
// 发起人类
class ChessGame {
private state: string;
constructor() {
this.state = ''; // 初始状态,可以是棋盘的表示等
}
public playMove(move: string): void {
// 执行棋步并更新状态
this.state += move + ';';
}
public save(): ChessMemento {
// 保存当前状态
return new ChessMemento(this.state);
}
public restore(memento: ChessMemento): void {
// 恢复到之前的状态
this.state = memento.getState();
}
public showState(): void {
console.log(this.state);
}
}
// 管理者类
class ChessCaretaker {
private mementos: ChessMemento[] = [];
public saveMemento(memento: ChessMemento): void {
this.mementos.push(memento);
}
public getMemento(index: number): ChessMemento {
return this.mementos[index];
}
}
// 客户端代码
const game = new ChessGame();
const caretaker = new ChessCaretaker();
// 玩家下棋步
game.playMove('e4');
game.playMove('e5');
caretaker.saveMemento(game.save()); // 保存当前状态
game.playMove('Nf3');
caretaker.saveMemento(game.save()); // 保存新状态
// 悔棋操作
game.restore(caretaker.getMemento(0)); // 恢复到第一次保存的状态
game.showState(); // 显示当前棋盘状态
如果用解释器来写呢?
// 定义一个抽象表达式接口
interface Expression {
interpret(): void;
}
// 定义一个具体表达式(移动棋子)
class MoveExpression implements Expression {
private chessboard: Chessboard;
private from: string;
private to: string;
constructor(chessboard: Chessboard, from: string, to: string) {
this.chessboard = chessboard;
this.from = from;
this.to = to;
}
interpret(): void {
this.chessboard.move(this.from, this.to);
}
}
// 定义一个具体表达式(悔棋)
class UndoExpression implements Expression {
private chessboard: Chessboard;
constructor(chessboard: Chessboard) {
this.chessboard = chessboard;
}
interpret(): void {
this.chessboard.undo();
}
}
// 定义一个解释器(棋盘)
class Chessboard {
private board: string[][];
constructor() {
this.board = [['♜', '♞', '♝', '♛', '♚', '♝', '♞', '♜'],
['♟', '♟', '♟', '♟', '♟', '♟', '♟', '♟'],
[' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '],
[' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '],
[' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '],
[' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '],
['♙', '♙', '♙', '♙', '♙', '♙', '♙', '♙'],
['♖', '♘', '♗', '♕', '♔', '♗', '♘', '♖']];
}
move(from: string, to: string): void {
// 移动棋子
}
undo(): void {
// 悔棋
}
interpret(expression: Expression): void {
expression.interpret();
}
}
// 使用解释器模式
const chessboard = new Chessboard();
const moveExpression = new MoveExpression(chessboard, 'e2', 'e4');
const undoExpression = new UndoExpression(chessboard);
chessboard.interpret(moveExpression); // 移动棋子
chessboard.interpret(undoExpression); // 悔棋
状态模式(State Pattern)和备忘录模式(Memento Pattern)都是行为设计模式,它们在处理对象状态方面有所涉及,但它们的目的、实现方式和应用场景有显著的不同。
尽管状态模式和备忘录模式都涉及对象的状态,但它们的设计目的和使用方式有明显的区别。状态模式关注于对象行为的动态变化,而备忘录模式关注于对象状态的保存和恢复。
围棋,状态模式
// 状态接口
interface ChessState {
playMove(move: string): void;
showState(): void;
}
// 具体状态类
class ChessMoveState implements ChessState {
private moves: string[] = [];
constructor(moves?: string[]) {
if (moves) {
this.moves = moves.slice(); // 创建移动列表的副本
}
}
public playMove(move: string): void {
this.moves.push(move);
}
public showState(): void {
console.log(this.moves.join('; '));
}
public clone(): ChessMoveState {
// 创建当前状态的副本
return new ChessMoveState(this.moves);
}
}
// 上下文类
class ChessGame {
private currentState: ChessMoveState;
constructor() {
this.currentState = new ChessMoveState();
}
public playMove(move: string): void {
this.currentState.playMove(move);
}
public save(): ChessMoveState {
return this.currentState.clone();
}
public restore(state: ChessMoveState): void {
this.currentState = state.clone();
}
public showState(): void {
this.currentState.showState();
}
}
// 客户端代码
const game = new ChessGame();
const savedStates: ChessMoveState[] = [];
// 玩家下棋步
game.playMove('e4');
game.playMove('e5');
savedStates.push(game.save()); // 保存当前状态
game.playMove('Nf3');
savedStates.push(game.save()); // 保存新状态
// 悔棋操作
game.restore(savedStates[0]); // 恢复到第一次保存的状态
game.showState(); // 显示当前棋盘状态
将请求封装成对象,从而使您可以用不同的方式对请求进行参数化、排队和执行。
当需要将请求与执行请求的对象解耦时。例如
命令模式结构图中包含如下几个角色:
JavaScript代码实现
// 命令接口
interface Command {
execute(): void;
undo(): void;
}
// 电灯类
class Light {
public on(): void {
console.log('Light is on');
}
public off(): void {
console.log('Light is off');
}
}
// 风扇类
class Fan {
public start(): void {
console.log('Fan is running');
}
public stop(): void {
console.log('Fan is stopped');
}
}
// 电灯开关命令
class LightOnCommand implements Command {
private light: Light;
constructor(light: Light) {
this.light = light;
}
public execute(): void {
this.light.on();
}
public undo(): void {
this.light.off();
}
}
// 电灯关命令
class LightOffCommand implements Command {
private light: Light;
constructor(light: Light) {
this.light = light;
}
public execute(): void {
this.light.off();
}
public undo(): void {
this.light.on();
}
}
// 风扇开命令
class FanStartCommand implements Command {
private fan: Fan;
constructor(fan: Fan) {
this.fan = fan;
}
public execute(): void {
this.fan.start();
}
public undo(): void {
this.fan.stop();
}
}
// 风扇关命令
class FanStopCommand implements Command {
private fan: Fan;
constructor(fan: Fan) {
this.fan = fan;
}
public execute(): void {
this.fan.stop();
}
public undo(): void {
this.fan.start();
}
}
// 调用者类
class RemoteControl {
private onCommands: Command[];
private offCommands: Command[];
private undoCommand: Command;
constructor() {
this.onCommands = [];
this.offCommands = [];
this.undoCommand = null!;
}
public setCommand(slot: number, onCommand: Command, offCommand: Command): void {
this.onCommands[slot] = onCommand;
this.offCommands[slot] = offCommand;
}
转载本站文章《再谈23种设计模式(3):行为型模式(学习笔记)》, 请注明出处:https://www.zhoulujun.cn/html/theory/engineering/model/9086.html
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。