简介
策略模式(Strategy Pattern)属于行为型设计模式。将每一个算法封装到具有共同接口的独立类中,根据需要来绑定策略,使得具体实现和策略解耦。
当你想使用对象中各种不同的算法变体,使用if…else 所带来的复杂和难以维护,可使用策略模式。或者当有许多相同类,它们仅在执行某些行为时略有不同,可使用策略模式。
作用
- 策略算法可以自由切换,保持策略与执行类的松耦合。
- 避免使用多重条件判断,不同环境角色可以组装多个策略。
- 扩展性良好,可以随时增删策略行为。
- 体现了多用组合,少用继承。
实现步骤
- 建立一个策略接口。
- 新建多个策略行为类,实现该策略接口。
- 建立一个抽象环境角色类,并将策略接口组合进来。是否需要抽象类可选。
- 建立多个环境角色类来继承该抽象类。
- 可以动态改变环境角色的策略行为。
不同语言设计模式源码下载:
https://github.com/microwind/design-pattern
UML
Java代码状态基础接口
// Strategy.java 基础策略接口public interface Strategy { public void run();}
策略实现类
// StrategyA.java 策略Apublic class StrategyA implements Strategy { @Override public void run() { System.out.println("StrategyA::run()."); }}
// StrategyB.java 策略Bpublic class StrategyB implements Strategy { @Override public void run() { System.out.println("StrategyB::run()."); }}
// StrategyC.java 策略Cpublic class StrategyC implements Strategy { @Override public void run() { System.out.println("StrategyC::run()."); }}
抽象业务类
// Context.java 抽象业务类,聚合策略对象public abstract class Context { protected Strategy strategy; public void setStrategy(Strategy strategy) { this.strategy = strategy; } public void action() { this.strategy.run(); }}
具体业务类
// ContextCat.java 业务类构造器聚合了某策略public class ContextCat extends Context { public ContextCat() { // 使用某个策略 System.out.println("ContextCat::setStrategy(StrategyC)."); this.setStrategy(new StrategyC()); }}
// ContextDog.java 业务类构造器聚合了某策略public class ContextDog extends Context { public ContextDog() { // 使用某个策略 System.out.println("ContextDog::setStrategy(StrategyB)."); this.setStrategy(new StrategyB()); }}
测试调用
/** * 策略模式就是根据需要给对象绑定具体策略,使得具体实现和策略可以灵活搭配。 * 先声明某个具体Context对象,该对象已经绑定了具体策略,同时还可以更改策略。 */ // 实例化某个内容,策略已经绑定上 Context contextCat = new ContextCat(); contextCat.action(); // 重新设置策略 System.out.println("reset contextCat'strategy to StrategyA."); contextCat.setStrategy(new StrategyA()); contextCat.action(); // 实例化某个内容,策略已经绑定上 Context contextGog = new ContextDog(); contextGog.action();
Go代码状态基础接口
// Strategy.go 基础策略接口// 定义一个策略接口,注意go语言数据类型即接口type Strategy interface { Run()}// 写在接口文件的其他全局方法func Init() { fmt.Println("strategy init!")}
策略实现类
// StrategyA.go 策略Atype StrategyA struct {}// 实现策略接口的对应方法func (s *StrategyA) Run() { fmt.Println("StrategyA::Run")}
// StrategyB.go 策略Btype StrategyB struct {}// 实现策略接口的对应方法func (s *StrategyB) Run() { fmt.Println("StrategyB::Run")}
// StrategyC.go 策略Ctype StrategyC struct {}// 实现策略接口的对应方法func (s *StrategyC) Run() { fmt.Println("StrategyC::Run")}
抽象业务类
// Context.go 抽象业务类,聚合策略对象type Context struct { strategy Strategy}// 设置不同strategy,方法名首字母大写func (c *Context) SetStrategy(s Strategy) { c.strategy = s}// 执行策略接口里面的方法func (c *Context) Run() { c.strategy.Run()}
具体业务类
// ContextCat.go 业务类构造器聚合了某策略// 定义具体执行对象,Go没有继承,用聚合来调用Context里的函数type ContextCat struct { context Context}// 可提前绑定具体的策略func (c *ContextCat) Init() { c.context.SetStrategy(&StrategyC{}) fmt.Println("ContextCat::init. setStrategy(StrategyC)")}// 调用策略方法func (c *ContextCat) Run() { fmt.Println("ContextCat::run") c.context.Run()}
// ContextDog.go 业务类构造器聚合了某策略type ContextDog struct { context Context}// 可提前绑定具体的策略func (c *ContextDog) Init() { c.context.SetStrategy(&StrategyB{}) fmt.Println("ContextDog::init. setStrategy(StrategyB)")}// 调用策略方法func (c *ContextDog) Run() { fmt.Println("ContextDog::run") c.context.Run()}
测试调用
func main() { fmt.Println("test start:") // 这里src.Init来自strategy.go文件 src.Init() /** * 策略模式就是根据需要给对象绑定具体策略,使得具体实现和策略可以灵活搭配。 * 先声明某个具体Context对象,该对象已经绑定了具体策略,同时还可以更改策略。 */ // 声明策略执行对象 context := src.Context{} // 设置策略A context.SetStrategy(&src.StrategyA{}) // 执行策略A,打印StrategyA context.Run() // 设置策略B context.SetStrategy(&src.StrategyB{}) // 执行策略B,打印StrategyB context.Run() // 执行策略C,打印StrategyC context.SetStrategy(&src.StrategyC{}) context.Run() // /*********************** 分割线 ******************************************/ // 直接实例化具体执行对象,策略已经绑定 contextCat := src.ContextCat{} contextCat.Init() contextCat.Run() // 直接实例化具体执行对象,策略已经绑定 contextDog := src.ContextDog{} contextDog.Init() contextDog.Run()}
更多语言版本
不同语言设计模式源码:https://github.com/microwind/design-pattern