策略模式定义
策略模式(Strategy Pattern)中定义一系列算法,并将每一个算法封装起来,使它们可以相互替换,策略模式让算法独立于使用它的客户而变化。
有许多算法可以实现同一功能,比如存在多种搜索算法、排序算法等。如果将这些算法硬编码在程序中,则会导致系统变得庞大而难以维护,在增加新的算法或改变现有算法时也将变得十分困难。为了解决类似问题,可以定义一些独立的类来封装不同的算法,每一个封装算法的类成为策略。
策略模式把算法的责任和算法本身分割开,委派给不同的对象管理。策略模式使用起来很方便,如需要提供一个灵活的网站搜索工具,可以有多种搜索策略,并且还会在以后根据实际情况增加新的搜索方式,就可以使用策略模式,创建一个搜索管理器用于和外部环境代码交互,在外部代码中针对抽象层编程,从而使得新的搜索方式出现时外部代码无需做任何改变,同时使得搜索算法的重用变得更为灵活。
策略模式结构图
图中:
Context表示环境类,它通过ConcreteStrategy对象配置其执行环境,并维护一个对Strategy的引用实例,可以定义一个接口供Strategy存取其数据;
Strategy表示抽象策略类,它定义一个公共的接口给所有支持的算法,Context可以使用这个接口调用ConcreteStrategy定义的算法;
ConcreteStrategyA和ConcreteStrategyB表示具体策略类,它们实现Strategy接口定义的算法。
策略模式实例——电影票打折
实例说明
某电影院售票系统为不同类型的用户提供了不同的打折方式(Discount),学生凭学生证可享受8折优惠(StudentDiscount),儿童可享受减免10元的优惠(ChildrenDiscount),VIP用户除享受半价优惠外还可以进行积分(VIPDiscount)。使用策略模式设计该系统,结合场景绘制相应的类图并编码实现。
实例类图
实例类图中与策略模式结构图对应的类主要有:
MovieTicket为环境类;
Discount为抽象策略类;
StudentDiscount、ChildrenDiscount和VIPDiscount为具体策略类。
实例代码
MovieTicket.java:
//电影票类:环境类 |
Discount.java:
//折扣类:抽象策略类 |
StudentDiscount.java:
//学生折扣类:具体策略类 |
ChildrenDiscount.java:
//儿童折扣类:具体策略类 |
VIPDiscount.java:
//VIP用户折扣类:具体策略类 |
Client.java:
//客户端测试类 |
运行结果
附加描述
在本实例中,可以通过配置文件来存储具体策略类的类名,再使用反射机制生产对象,如果需要更换具体策略或使用新增加的具体策略,无需修改任何源代码(包括客户端代码),只需修改配置文件即可,完全符合开闭原则。
后话
学习设计模式,是一场修行。