策略模式:
1、定义:定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户
2、模型结构:
(1)抽象策略(Strategy)类:定义了一个公共接口,各种不同的算法以不同的方式实现这个接口,
环境角色使用这个接口调用不同的算法,一般使用接口或抽象类实现
(2)具体策略(Concrete Strategy)类:实现了抽象策略定义的接口,提供具体的算法实现
(3)环境(Context)类:持有一个策略类的引用,最终给客户端调用
3、优点:
(1)使用策略模式可以避免使用多重条件转移语句
(2)提供一系列可供重用的算法族,恰当使用继承可以把算法族的公共代码转移到父类里面,从而避免重复的代码
(3)提供了对“开闭原则”的完美支持,在不修改原有系统的基础上选择算法或行为,也可灵活地增加新算法或行为
(4)策略模式可以提供相同行为的不同实现,客户可根据不同的要求选择不同的实现
(5)策略模式把算法的使用放到环境类中,而算法的实现移到具体策略类中,实现了二者的分离
4、缺点:
(1)客户端必须理解所有策略算法的区别,以便适时选择恰当的算法类
(2)策略模式将造成产生很多策略类,可以通过使用享元模式在一定程度上减少对象的数量
5、适用环境:
(1)一个系统需要动态地在几种算法中选择一种
(2)一个类定义了多种行为,并且这些行为在这个类的操作中以多个条件语句的形式出现,
可将每个条件分支移入它们各自的策略类中以代替这些条件语句
(3)不希望客户端知道复杂的、与算法相关的数据结构,在具体策略类中封装算法和相关的数据结构,
提高算法的保密性与安全性
(4)多个类只区别在表现行为不同,可以使用策略模式,在运行时动态选择具体要执行的行为
(5)系统中各算法彼此完全独立,且要求对客户隐藏具体算法的实现细节时
// 购买门票策略(门票每张10元): 1、超过25张的打九折 2、15张票送一张 // 抽象策略类 abstract class Strategy { protected price: number = 10; // 门票价格 protected total: number; // 门票总花费 // 根据方案不同计算总花费 abstract strategyMethod(num: number): void; } // 具体策略类,超过25张的打九折 class ConcreteStrategyA extends Strategy { strategyMethod(num: number): void { this.total = num > 25 ? 25*this.price+(num-25)*this.price*0.9 : num*this.price; console.log(`方法 1 购买 ${num} 张票花费 ${this.total} 元`); } } // 15张票送一张 class ConcreteStrategyB extends Strategy { strategyMethod(num: number): void { this.total = 15*this.price*((num-num%16)/16) + (num%16)*this.price; console.log(`方法 2 购买 ${num} 张票花费 ${this.total} 元`); } } // 环境类 class StrategyContext { private strategy: Strategy; getStrategy(): Strategy { return this.strategy; } setStrategy(strategy: Strategy) { this.strategy = strategy; } strategyMethod(num: number): void { this.strategy.strategyMethod(num); } } let fares: number = 100; let strategyContext: StrategyContext = new StrategyContext(); let strategy1: Strategy = new ConcreteStrategyA(); strategyContext.setStrategy(strategy1); strategyContext.strategyMethod(fares); // 方法 1 购买 100 张票花费 925 元 let strategy2: Strategy = new ConcreteStrategyB(); strategyContext.setStrategy(strategy2); strategyContext.strategyMethod(fares); // 方法 2 购买 100 张票花费 940 元 // 目前环境里的策略为 strategy2,所以输出:方法 2 购买 100 张票花费 940 元 strategyContext.getStrategy().strategyMethod(fares);
模板方法模式:
1、定义:定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,
使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤
2、模型结构:
(1)抽象类(Abstract Class):负责给出一个算法的轮廓和骨架,它由一个模板方法和若干个基本方法构成
(2)具体子类(Concrete Class):实现抽象类中所定义的抽象方法和钩子方法,它们是一个顶级逻辑的一个组成步骤
注:
(1)模板方法:定义了算法的骨架,按某种顺序调用其包含的基本方法
(2)基本方法:是整个算法中的一个步骤,包含以下几种类型
A、抽象方法:在抽象类中申明,由具体子类实现
B、具体方法:在抽象类中已经实现,在具体子类中可以继承或重写它
C、钩子方法:在抽象类中已经实现,包括用于判断的逻辑方法和需要子类重写的空方法两种
3、优点:
(1)封装了不变部分,扩展可变部分:它把认为是不变部分的算法封装到父类中实现,
而把可变部分算法由子类继承实现,便于子类继续扩展
(2)在父类中提取公共部分的代码,便于代码复用
(3)部分方法是由子类实现的,因此子类可以通过扩展方式增加相应的功能,符合“开闭原则”
4、缺点:
(1)对每个不同的实现都需要定义一个子类,这会导致类的个数增加,系统更加庞大,设计也更加抽象
(2)父类中的抽象方法由子类实现,子类执行的结果会影响父类的结果,
这导致一种反向的控制结构,它提高了代码阅读的难度
5、适用环境:
(1)算法的整体步骤很固定,但其中个别部分易变时,这时候可以使用模板方法模式,
将容易变的部分抽象出来,供子类实现
(2)当多个子类存在公共的行为时,可以将其提取出来并集中到一个公共父类中以避免代码重复。
首先,要识别现有代码中的不同之处,并且将不同之处分离为新的操作。
最后,用一个调用