JAVA设计模式 之 策略模式
一. 定义
设计模式定义了算法族,分别封装起来,让他们之间可以互相替代,此模式让算法的变化独立于使用算法的客户(该定义来自于Head First 设计模式)。
二. 应用场景
当我们在应用程序中完成一项功能时,有些需要经常变化的算法我们需要就独立的抽取出来,将使用抽象的引用为在具体的功能类中标示,并且在程序运行时能够动态的改变这些算法功能。
三. 设计原则
设计模式告诉我们:
(1). 找出应用中可能需要变化之处,把他们独立出来,不要和那些不需要变化的代码混在一起。
(2). 要针对接口编程,而不是针对实现的编程。
(3). 多用组合,少用继承。
四. 举例说明
假如某超级市场有这样的会员打折行为,会员分为三个等级,这里就用A,B,C来替代,会员A具有一种算法,会员B具有一种算法,会员C也具有一种算法。因为以后可能有更多的会员计算方法或者按不同节日为会员打折等,使用JAVA我们一般的做法是创建一个类,在类中判断如果是会员A我们就按照一种计算方法结账,如果是会员B我们就会用另外以一种方法结账,如果是会员C我们在用一种结账算法,这样呢这个类中就多了很多if ... else 判断,并且这个方法相当的长,问题就暴露出来了,日后你可能不愿意维护这样的代码,但是有的人说了,我把不同的算法都提出来为一个方法不行行了吗?恩,很对,那么在if...else里面就可以减少代码量了,可是如果超级市场有新增加了新的会员,或者会员算法需要修改的时候,问题是不是又来了,所以为了使日后维护方便,做到最少的修改,即满足开闭原则,这里使用策略模式来解决该问题。
策略模式解决该问题的思路是将具体的不同的会员算法提出来作为一个类,然后呢实现一个统一的接口,这样在日后增加了一个会员算法,只需要添加一种实现而已,然后在超市的这个类中持有这个会员算法的接口引用即可。
封装行为类图:
具体看如下代码:
1. 会员结账接口 ISettleAccounts.java
/** * 会员结账接口 * @author Administrator */ public interface ISettleAccounts { /** * 计算账目 * @return */ public double calculate(double reallyPrice); }
2. 会员A打折算法 MemberA.java 继承统一的会员结账接口
public class MemberA implements ISettleAccounts { public double calculate(double reallyPrice) { System.out.println("MemberA 的账目计算方法[9折计算]....."); return reallyPrice * 90/100; } }
3. 会员B打折算法 MemberB.java 继承统一的会员结账接口
public class MemberB implements ISettleAccounts { public double calculate(double reallyPrice) { System.out.println("MemberB 的账目计算方法[8.5折计算]....."); return reallyPrice * 85/100; } }
3. 会员C打折算法 MemberC.java 继承统一的会员结账接口
public class MemberC implements ISettleAccounts { public double calculate(double reallyPrice) { System.out.println("MemberA 的账目计算方法[8折计算]....."); return reallyPrice * 80/100; } }
4. 超级市场类Supermarket.java
/** * 超级市场 * @author Administrator */ public abstract class Supermarket { // 持有结账引用 private ISettleAccounts settleAccounts; // 其它的属性 // private ...... // 可以设置某一种会员打折类别,也就是在运行的时候可以改变某种会员计算方法 public void setSettleAccounts(ISettleAccounts settleAccounts) { this.settleAccounts = settleAccounts; } /** * 打折计算 * @param reallyPrice * @return */ public double discount(double reallyPrice){ return settleAccounts.calculate(reallyPrice); } // 其它的方法 // public ...... }
5. 顾客会员A CustomerMemberA.java 类
在这个顾客类中只需要将会员A的算法动态的设置其中即可。当然你还可以创建顾客会员B,顾客会员C。。。。
/** * 客户会员A * @author Administrator */ public class CustomerMemberA extends Supermarket { // 构造客户会员A public CustomerMemberA(){ super.setSettleAccounts(new MemberA()); } }
6. 测试类 CustomerMemberATest.java
/** * 会员A来超级市场购物结账,并且实际消费是1200元 * @author Administrator */ public class CustomerMemberATest extends Supermarket { public static void main(String[] args) { // 创建客户会员A CustomerMemberA customerMemberA = new CustomerMemberA(); System.out.println(customerMemberA.discount(1200)); } }
7. 运行测试结构
MemberA 的账目计算方法[9折计算]..... 1080.0