一、场景:在实际的项目开发中,我们常常会遇到这样的问题,实现一个功能有多重方法或策略。
比如商场中计算价格的方法:
1、商场中没有活动,那么收费就是原价;
2、商场中有活动,打8折;
3、商场中有活动,满300件100;
这三个中计算价格的方法就是三种策略。我们在不适用设计模式的情况下,就只能用if...else...获取switch..case..来判断使用哪一中计算方法,如下代码块:
/**
* 增加打折功能,在客户端增加一个折扣下拉选,打8折、7折、5折
* @param price 单价
* @param count 数量
* @param discount 折扣
* @return
*/
public Double calculation2(Double price,Double count,String discount){
Double result=0D;
if(price==null || count==null){
return result;
}
switch (discount) {
case "打8折":
result=price*count*0.8;
break;
case "打7折":
result=price*count*0.7;
break;
case "打5折":
result=price*count*0.5;
break;
default:
result=price*count;
break;
}
return result;
}
这样写可以实现搞活动的功能,但是这样写代码属于硬编码,如果商场中不搞活动了或者新增加了一种活动规则,我们就需要重写代码,扩展性不好,因此考虑使用策略模式。
二、策略模式
2.1 定义
策略模式(Strategy)定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化,不会影响到使用算法的客户。
2.2 结构
2.3 商场搞活动代码实现
(1)、抽象算法类,抽象出了计算价格的算法。
abstract class CushSuper {
public abstract double attachMoney(double money);
}
(2)、具体算法1,正常收费
public class CushNormal extends CushSuper{
@Override
public double attachMoney(double money) {
return money;
}
}
(3)、具体算法2,打折收费
public class CushRebate extends CushSuper{
private double cushRebate=1d;
public CushRebate(String moneyRebate) {
this.cushRebate=Double.parseDouble(moneyRebate);
}
/*
* <p>折扣收费 </p>
* @param money
* @return
*/
@Override
public double attachMoney(double money) {
double result=money*cushRebate;
return result;
}
}
(4)、具体算法3,满减收费
public class CushReturn extends CushSuper{
private double cushContidion=0d;
private double cushReturn=0;
public CushReturn(String cushContidion,String cushReturn) {
this.cushContidion=Double.parseDouble(cushContidion);
this.cushReturn=Double.parseDouble(cushReturn);
}
/*
* <p>满减收费 </p>
* @param money
* @return
*/
@Override
public double attachMoney(double money) {
double result=money-Math.floor(money/cushContidion)*cushReturn;
return result;
}
}
(5)、context上下文,维护一个对Strategy对象的引用。
public class CushContxt {
private CushSuper cushSuper;
public CushContxt(CushSuper cushSuper) {
this.cushSuper=cushSuper;
}
public double getResult(double money){
return cushSuper.attachMoney(money);
}
}
(6)、客户端使用
public class Test {
public static void main(String[] args) {
double price=10d;
double count=3d;
//计算总价
Double money=price*count;
//获取输入框中的类型
// String type="正常收费";
String type="打8折";
// String type="打5折";
// String type="满300减100";
CushContxt content=null;
switch (type) {
case "正常收费":
content=new CushContxt(new CushNormal());
break;
case "打8折":
content=new CushContxt(new CushRebate("0.8"));
break;
case "打5折":
content=new CushContxt(new CushRebate("0.5"));
break;
case "满300减100":
content=new CushContxt(new CushReturn("300","100"));
break;
}
if(content!=null){
System.out.println(content.getResult(money));
}
}
}
至此,策略模式的解释已经结束,可以看出以上代码的优缺点:
优点:1、算法可以自由切换。 2、避免使用多重条件判断。 3、扩展性好。
缺点:1、客户端必须知道所有的策略类,并自己决定由那个策略类。 2、策略类会很多。
解决这个缺点方法:策略+简单工厂
三、策略+简单工厂
为了解决客户端必须知道所有的策略类,并自己决定由那个策略类这个缺点,可以使用策略+工厂模式。
改进CushContext类如下:
public class CushContext {
CushSuper cushSuper=null;
public CushContext(String type) {
switch (type) {
case "正常收费":
cushSuper=new CushNormal();
break;
case "打8折":
cushSuper=new CushRebate("0.8");
break;
case "打5折":
cushSuper=new CushRebate("0.5");
break;
case "满300减100":
cushSuper=new CushReturn("300","100");
break;
}
}
public double getResult(double money){
return cushSuper.attachMoney(money);
}
}
客户端改为:
public class Test {
//使用策略模式+简单工厂模式实现
public static void main(String[] args) {
double price=10d;
double count=3d;
//计算总价
Double money=price*count;
//获取输入框中的类型
String type1="正常收费";
String type2="打8折";
String type3="打5折";
String type4="满300减100";
CushContext content=new CushContext(type1);
//正常收费
System.out.println(content.getResult(money));
//打8折
CushContext content2=new CushContext(type2);
System.out.println(content2.getResult(money));
//打5折
CushContext content3=new CushContext(type3);
System.out.println(content3.getResult(money));
//满300减100
CushContext content4=new CushContext(type4);
System.out.println(content4.getResult(money));
}
}
优点:解决了需要在客户端判断使用那个实现的缺点;
缺点:在cashContext中用到了swith,也就是说,如果我们需要增加一种算法,比如"满200减50",就必须更改cashContext中的switch代码。
解决方法:策略+简单工厂+反射
四、策略+简单工厂+反射
改进CushContext类如下:
public class CushContext {
private static final String[] CUSH_CLASS_NAME = {
"main.java.celue.celue5.CushNormal",
"main.java.celue.celue5.CushRebate",
"main.java.celue.celue5.CushReturn"
};
CushSuper cushSuper=null;
public CushContext(String type,Class[] paramsType, Object[] parmas) {
int type2=Integer.parseInt(type);
try {
Class<?> clazz=Class.forName(CUSH_CLASS_NAME[type2]);
Constructor<?> constructor=clazz.getConstructor(paramsType);
this.cushSuper=(CushSuper)constructor.newInstance(parmas);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
public double getResult(double money){
return cushSuper.attachMoney(money);
}
}
客户端改进:
public class Test {
public static void main(String[] args) {
double price=100d;
double count=3d;
//计算总价
Double money=price*count;
//正常收费
Class[] paramTypes = {};
Object[] params = {};
CushContext context=new CushContext("0",paramTypes,params);
System.out.println(context.getResult(money));
//打8折
Class[] paramTypes2 = {String.class};
Object[] params2 = {"0.8"};
CushContext context2=new CushContext("1",paramTypes2,params2);
System.out.println(context2.getResult(money));
//打5折
Class[] paramTypes3 = {String.class};
Object[] params3 = {"0.5"};
CushContext context3=new CushContext("1",paramTypes3,params3);
System.out.println(context3.getResult(money));
//满300减100
Class[] paramTypes4 = {String.class,String.class};
Object[] params4 = {"300","100"};
CushContext context4=new CushContext("2",paramTypes4,params4);
System.out.println(context4.getResult(money));
}
}
以上就是策略模式的应用,由于本人是自己学习总结的,如果有写的不对的地方,欢迎各位大神批评指出。