我们写代码如果逻辑判断比较多的时候,if的情况比较复杂的时候是不是经常写出这样的代码:
就如上图一堆一堆的if-else判断,看的人眼花缭乱的。其实从代码的优雅角度来看这就是一堆辣鸡,根本拿不上台面。那么需要怎么优化一下类似上面的这么多if-else呢?
策略模式
经典兵法 《设计模式之禅》对于策略模式有个简单的定义:
定义一组算法,将每个算法都封装起来,并且使他们之间可以互换。。。。。Context叫做上下文角色,起承上启下封装作用,屏蔽高层模块对策略、算法的直接访问,封装可能存在的变化。。。。。
这描述的有点抽象,其实我们在实际开发中对于策略模式经常使用。只是我们没有过多的去思考和关注,举个例子:大家还记不记得ThreadPoolExecutor(线程池),jdk提供了几种线程池,但是我们使用的时候并不推荐使用jdk提供的。一般我们都需要根据构造函数自己去创建线程池(线程池相关知识和注意的点下次单独文章说)。我们自己构造线程池的时候有个名不见经传的7大参数之一RejectedExecutionHandler含义是拒绝策略(具体有四种实现:直接抛出异常、返回调用者的线程来处理、丢掉当前任务、丢掉最老的任务),其本质就是策略模式的体现。
/**
* Handler called when saturated or shutdown in execute.
*/
private volatile RejectedExecutionHandler handler;
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
//具体代码。。。
this.handler = handler;
}
/**
* Invokes the rejected execution handler for the given command.
* Package-protected for use by ScheduledThreadPoolExecutor.
*/
final void reject(Runnable command) {
handler.rejectedExecution(command, this);
}
来跟我看看这个策略模式
策略模式是一种定义一系列算法的方法
,从概念上来看,所有这些算法完成的都是相同的工作
,只是实现不同,他可以以相同的方式
调用所有的算法,减少了各种算法类与使用算法类之间的耦合。
从理论上看上边我高亮的部分。有以下几个特点:
策略模板:策略模式的算法都是为了完成相同的工作的,只是可能触发条件不同,所以我们就可以抽象出来一个策略模板。
策略:根据具体场景实现不同的策略,以根据实际场景得到具体的结果;
上下文:上下文根据场景不同来决定使用哪种策略。
举个生活中的例子帮助大家理解:我们都用过洗衣机,洗衣机洗东西的时候可以选择很多种类(快洗、标准,漂洗、大件等),这么多种类都是一个目的把东西洗好,知识洗的方式触发条件不同,所以我们可以把洗东西
这个动作抽象出来之后具体洗的种类
则是洗东西这个抽象的具体实现
。
策略模式代码示例
//洗的动作 -> 策略模板
class DoingWash {
constructor() {}
}
// 标准洗
class Biaozhun extends DoingWash {
constructor() {}
doWash() {
return "我是标准洗";
}
}
// 快速洗
class KuaiSu extends DoingWash {
constructor() {}
doWash() {
return "我是快速洗";
}
}
// 大件洗
class DaJian extends DoingWash {
constructor() {}
doWash() {
return "我是大件洗";
}
}
// 上下文传入策略并使用
class WashContext {
constructor(strategy) {
this.strategy = strategy;
}
doingGo() {
return this.strategy.doWash();
}
}
// 使用
WashContext w1 = new WashContext(new Biaozhun());
w1.doWash();
怎么样很简单吧。。。我们来总结一下策略模式:
由上面这么多的例子我们可以总结出来,策略模式的使用场景有几个特点:
- 面对一个问题/需求有多种解决策略,需要判断不同的场景
- 场景的数量较少
优点就是
: - 策略与策略之间相互独立,扩展性、维护性比较好
- 单元测试好做
- 减少了switch/if else判断
缺点就是
: - 不适合解决场景太多的情况
工厂方法模式
说完策略模式我们顺便在说一下工厂模式,因为二者很像。我们对比着看这样就能看出二者的区别,已经具体的模式应该在那种场景下使用。工厂模式是在简单工厂模式之上做了优化处理之后形成一种模式。工厂模式从定义上跟策略模式非常相似。
来跟我看看这个工厂方法模式
举个例子
:现在我一个运输的业务,将物品从国内的一个城市运输到另一个城市,那么我可以选择的运输方式就有多种,可以用汽车,可以用火车,也可以用飞机。这都是运东西的一个实现,也就是具体用什么运输。那么好我们就抽象出来一个概念叫运东西,具体去干这个运东西的事情由以上三种形式。我不关心使用何种工具进行运输,具体交由子类(火车
,飞机
,汽车
)去实现。
我们看个代码示例
class TransPortSThing {
constructor() {}
transGo() {
// 我只定义要运输具体怎么运输子类都要实现transGo方法
}
}
// 汽车
class Qiche extends TransPortSThing {
constructor() {}
transGo() {
return "我是汽车";
}
}
// 火车
class Huoche extends TransPortSThing {
constructor() {}
transGo() {
return "我是火车";
}
}
// 飞机
class FeiJi extends TransPortSThing {
constructor() {}
transGo() {
return "我是飞机";
}
}
// 使用 --用火车运输
TransPortSThing yunDongXi = new Huoche();
yunDongXi.transGo();
// 使用 --用飞机运输
TransPortSThing yunDongXi = new FeiJi();
yunDongXi.transGo();
以上代码在调用的时候可以编写工具类之后根据参数动态获取TransPortSThing类的那个子类对象之后进行调用。通过以上不难看出这两种设计模式很相似。
我们总结一下这个工厂方法模式:
- 避免创建者与具体的产品逻辑耦合。
- 满⾜单⼀职责,每⼀个业务逻辑实现都在所属⾃⼰的类中完成。
- 满⾜开闭原则,⽆需更改使⽤调⽤⽅就可以在程序中引⼊新的实现
二者的比较
我们能看出来以上2种设计模式很相似,我们具体比对一下,再总结一下
。用2个图说明一下:
这样大家就能直观的感受出来二者的不同了。
策略模式和工厂模式区别:
工厂模式
1.目的是创建不同且相关的对象
2.侧重于"创建对象"
3.实现方式上可以通过父类或者接口
4.一般创建对象应该是现实世界中某种事物的映射,有它自己的属性与方法!
策略模式
1.目的实现方便地替换不同的算法类
2.侧重于算法(行为)实现
3.实现主要通过接口
4.创建对象对行为的抽象而非对对象的抽象,很可能没有属于自己的属性。`
其实归根结底一句话(我觉得这句话我总结的十分准确):工厂方法模式中只管生产实例,具体怎么使用工厂实例由调用方决定,策略模式是将生成实例的使用策略放在策略类中配置后才提供调用方使用。 工厂方法模式调用方可以直接调用工厂方法实例的方法属性等,策略模式不能直接调用实例的方法属性,需要在策略类中封装策略后调用。