这些新的操作的模板方法来替换这些不同的代码
(3)当需要控制子类的扩展时,模板方法只在特定点调用钩子操作,这样就只允许在这些点进行扩展
// 假设早上上班步骤:1、起床 2、刷牙洗脸 3、吃早饭 4、坐车去公司 5、到达时间
// 抽象类
abstract class AbstractClass {
protected food: string;
protected vehicle: string;
protected time: string;
TemplateMethod(): void {
this.awake();
this.clean();
this.eat();
this.transportation();
this.arrive();
}
awake(): void {
console.log("Awaking on time...");
}
clean(): void {
console.log("Washing face and brushing teeth...");
}
abstract eat():void;
abstract transportation(): void;
abstract arrive(): void;
}
// 具体子类
class ConcreteClass extends AbstractClass {
constructor(food: string, vehicle: string, time: string) {
super();
this.food = food;
this.vehicle = vehicle;
this.time = time;
}
eat(): void {
console.log(`Eating ${this.food}`);
}
transportation(): void {
console.log(`Going to workplace by ${this.vehicle}`);
}
arrive(): void {
console.log(`Arriving workplace at ${this.time}`);
}
}
let food: string = "bread and milk";
let vehicle: string = "bus";
let time: string = "9:00 am";
let tm: AbstractClass = new ConcreteClass(food, vehicle, time);
tm.TemplateMethod();
访问者模式:

1、定义:将作用于某种数据结构中的各元素的操作分离出来封装成独立的类,
使其在不改变数据结构的前提下可以添加作用于这些元素的新的操作,
为数据结构中的每个元素提供多种访问方式
2、模型结构:
(1)抽象访问者(Visitor):定义一个访问具体元素的接口,为每个具体元素类对应一个访问操作 visit(),
该操作中的参数类型标识了被访问的具体元素
(2)具体访问者(ConcreteVisitor):实现抽象访问者中声明的各个访问操作,确定访问者访问一个元素时该做什么
(3)抽象元素(Element):声明一个包含接受操作 accept() 的接口,被接受的访问者对象作为 accept() 方法的参数
(4)具体元素(ConcreteElement):实现抽象元素角色提供的 accept() 操作,其方法体通常是 visitor.visit(this),
另外具体元素中可能还包含本身业务逻辑的相关操作
(5)对象结构(Object Structure):是一个包含元素角色的容器,提供让访问者对象遍历容器中的所有元素的方法
3、优点:
(1)扩展性好:能够在不修改对象结构中的元素的情况下,为对象结构中的元素添加新的功能
(2)复用性好:可以通过访问者来定义整个对象结构通用的功能,从而提高系统的复用程度
(3)灵活性好:将数据结构与作用于结构上的操作解耦,使操作集合可相对自由地演化而不影响系统的数据结构
(4)符合单一职责原则:把相关的行为封装在一起,构成一个访问者,使每一个访问者的功能都比较单一
4、缺点:
(1)增加新的元素类很困难:在访问者模式中,每增加一个新的元素类,
都要在每一个具体访问者类中增加相应的具体操作,这违背了“开闭原则”
(2)破坏封装:访问者模式中具体元素对访问者公布细节,这破坏了对象的封装性
(3)违反了依赖倒置原则:访问者模式依赖了具体类,而没有依赖抽象类
5、适用环境:
(1)对象结构相对稳定,但其操作算法经常变化的程序
(2)对象结构中的对象需要提供多种不同且不相关的操作,而且要避免让这些操作的变化影响对象的结构
(3)对象结构包含很多类型的对象,希望对这些对象实施一些依赖于其具体类型的操作
// 抽象访问者
interface Visitor {
visit(element: IElement): void;
}
// 具体访问者,篮球运动员和羽毛球运动员
class ConcreteVisitorA implements Visitor {
visit(element: IElement): void {
console.log(`篮球运动员:${element.operationA()}`);
}
}
class ConcreteVisitorB implements Visitor {
visit(element: IElement): void {
console.log(`羽毛球运动员:${element.operationB()}`);
}
}
// 抽象元素
interface IElement {
accept(visitor: Visitor): void;
operationA(): string;
operationB(): string;
}
// 具体元素,球类和工具类
class ConcreteElementA implements IElement {
accept(visitor: Visitor): void {
visitor.visit(this);
}
operationA(): string {
return "打篮球";
}
operationB(): string {
return "打羽毛球";
}
}
class ConcreteElementB {
accept(visitor: Visitor): void {
visitor.visit(this);
}
operationA(): string {
return "需要篮球鞋";
}
operationB():