不渴望能够一跃千里,只希望每天能够前进一步。
光阴易逝,岂容我待。
最近学习了下设计模式,发现了一些问题,记录下来。
目录
在总结上面三个问题回答之前,我们先来写一遍策略模式。
网上的策略模式有多种写法,这里只举栗2种:
首先是没用设计模式之前的代码:
public Result calcPrice(int customerType){
//判断客户类型执行不同计算价格方法
if(customerType == 1){
//计算白银客户优惠价..
}else if(customerType == 2){
//计算黄金客户优惠价..
}else if(customerType == 3){
//计算钻石客户优惠价..
}
.....
else{
//计算xx客户优惠价..
}
}
策略模式第一种写法:
在客户端根据传入的策略类来判断
//价格策略接口
public interface IPriceStrategy{
Result calcPrice();
}
//白银客户价格策略类
public class SilverPriceStrategy implements IPriceStrategy{
Result calcPrice(){
//计算白银客户优惠价..
}
}
//黄金客户价格策略类
public class GoldPriceStrategy implements IPriceStrategy{
Result calcPrice(){
//计算黄金客户优惠价..
}
}
//钻石客户价格策略类
public class DiamondPriceStrategy implements IPriceStrategy{
Result calcPrice(){
//计算钻石客户优惠价..
}
}
...
//价格策略上下文类
public class CustomerPriceContext{
private IPriceStrategy iPriceStrategy;
public CustomerPriceContext(IPriceStrategy iPriceStrategy){
this.iPriceStrategy = iPriceStrategy;
}
public Result calcPrice(){
return this.iPriceStrategy.calcPrice();
}
}
===========================================================================
//客户端调用
public Result calcPrice(){
//计算白银客户优惠价..
CustomerPriceContext context = new CustomerPriceContext(new SilverPriceStrategy());
Result result = context.calcPrice();
//计算黄金客户优惠价..
CustomerPriceContext context = new CustomerPriceContext(new GoldPriceStrategy());
Result result = context.calcPrice();
//计算钻石客户优惠价..
CustomerPriceContext context = new CustomerPriceContext(new DiamondPriceStrategy());
Result result = context.calcPrice();
...
//计算xx客户优惠价..
CustomerPriceContext context = new CustomerPriceContext(new XXPriceStrategy());
Result result = context.calcPrice();
}
写完后,嗯,大家是不是感觉有点怪怪的?
没错,我也觉得怪怪的。
我在网络上浏览了很多讲策略模式的帖子,他们都是用上面的写法作为例子,然后结束总结策略模式优点的时候提到:策略模式可以省略掉if else,让你的代码更加优雅
优雅个鬼啊!
在客户端不还是要写if else来判断new哪个策略方法吗?只是他们例子没有写出来,这样自欺欺人???
那策略模式可以省略if else吗?可以!不过写法是下面第二种写法:
在客户端传入客户类型字符串判断
//价格策略接口
public interface IPriceStrategy{
Result calcPrice();
}
//白银客户价格策略类
public class SilverPriceStrategy implements IPriceStrategy{
Result calcPrice(){
//计算白银客户优惠价..
}
}
//黄金客户价格策略类
public class GoldPriceStrategy implements IPriceStrategy{
Result calcPrice(){
//计算黄金客户优惠价..
}
}
//钻石客户价格策略类
public class DiamondPriceStrategy implements IPriceStrategy{
Result calcPrice(){
//计算钻石客户优惠价..
}
}
...
//价格策略上下文类
public class CustomerPriceContext{
//通过hashmap来将判断条件与处理函数做个映射
private final static HashMap<String,IPriceStrategy> strategyMap = new HashMap<>();
static{
strategyMap.put("silver",new SilverPriceStrategy());
strategyMap.put("gold",new GoldPriceStrategy());
strategyMap.put("diamond",new DiamondPriceStrategy());
...
strategyMap.put("xx",new CStrategy());
}
private String customerType;
public CustomerPriceContext(String customerType){
this.customerType = customerType;
}
public Result calcPrice(){
return this.strategyMap.get(this.customerType).calcPrice();
}
}
===========================================================================
//客户端调用
public Result calcPrice(int customerType){
String customerTypeDesc = getCustomerTypeDesc(customerType);
CustomerPriceContext context = new CustomerPriceContext(customerType);
Result result = context.calcPrice();
}
这第二种策略模式写法是利用的hashmap来取消if else的,所以我们这第二个问题:策略模式真的能省略if else 判断吗?我想你心中应该有了答案。
对比一、二两种方式,看你们喜欢用哪种咯。
反正我个人是更喜欢第二种方式哈哈哈哈。
因为第一种写法还是要写if else,这样在以后有新的客户类型加入后,你需要修改客户端类,在客户端新增if else,这并没有完全解耦合,另外万一有多处地方都调用了呢,那只能一个一个改咯。
而第二种写法不需要写if else了,他让客户端和计算价格模块完全解耦合,以后新增了客户类型不需要修改客户端的代码,仅仅修改这个价格策略模块的代码即可。
好了,看到这里,肯定有人发现了,这策略模式怎么和工厂模式这么像?请往下看
1、工厂模式和策略模式有什么区别?
嗯,还是先说说我在网上浏览帖子的情况,大家都说:
编辑
是不是看的头大?反正我是
我觉得吧,上面写的第一种策略模式和简单工厂模式差不多
上面写的第二种策略模式和工厂模式差不多
差异在哪呢?
代码差异: 工厂模式用的是factory命名。。。策略模式是用的Context上下文类。。老实讲我觉得差别不大,也就换换变量名加几个属性。
使用目的差异: 工厂模式当然是为了生产对象,只生产对象。而策略模式不是,策略模式是根据你传的参数来选择执行策略。他们直接的差别就是:工厂模式要生产一个给别人用的对象,策略模式要执行某段封装好的逻辑,可能有返回也可能没返回。
设计模式类型差异: 一个是创建型设计模式、一个是行为型设计模式。
阅读代码的时候的差异: 当我看到factory这个单词的时候,便能知道以后想获得个对象的时候,可以调用他的方法,当我看到strategy或者context这两单词的时候,我能联想到策略模式,要修改策略逻辑时能快速定位到需要修改的地方,而且修改范围不会大。
看完的大佬轻喷 -_-
2、策略模式真的能省略if和else判断吗?
不能,看上面的两种策略模式方式就能明白,省略if else的功劳hashmap更大一点。
3、策略模式是否有必要写个上下文类()Context?
有必要。
因为实际开发并不像我举的例子这么简单,肯定有数据交互的啦,往往各个策略需要的数据又不完全一样,会有重复也会有差异,引入了context后,我们的客户端就只要和context打交道,数据交互也是由context和策略类直接交互,可以理解为context是一个缓冲地带,在这里我们可以在调用策略类之前做些小动作、处理策略类需要的数据。
然后如果有策略类被删除或者新增替换,又或者是改名,在被很多模块调用的情况下,需要一个一个去修改,容易出错又麻烦。引入context后只用修改context的映射就可以了。
传送门:
(77条消息) isS1mple??的博客_CSDN博客-领域博主