前言
设计模式是指导一个程序猿以更好的姿态处理一些问题,而不再像刚学编程的我们,只会使用if-else分支语句,或是使用硬干的骚操作完成需求。不使用设计模式,一来是代码逻辑会越来越晦涩难懂(到了某天你会发现自己也没办法看清楚所有逻辑),二来是代码维护成本越来越高(你的加班时间会越来越长),三来是可以装bility。基于这么多的好处,小盆友和大家一起讨论和分享下设计模式,让自己不再是一个坐在电脑前敲代码的码农。
讲个小故事——“半百老人迎娶貌美孙小妹”
讲模式前,老套路,先讲个小故事。
今天借用下三国的一个经典场景,孙权想夺回荆州,于是想将孙小妹“嫁”给刘备,让刘备来吴迎娶小妹。但嫁给刘备是假,软禁刘备是真。于是小亮让赵云随行,并且给了三个锦囊,让其在危机时刻打开,化险为夷。三个锦囊是找乔国老帮帮忙,找吴国太帮帮忙,找孙小妹帮帮忙。故事在《三国演义》中写的很精彩,我在这就不讲书了,有兴趣的猿们,可以自行翻阅,增加自己一点bi气。
现在用猿的视线分析下刚才的场景,赵云只是一个使用锦囊的用户,随身携带了三个算法(锦囊),具体是什么算法,赵云不知道,只知道遇到第一个困难就用第一个,第二个困难就用第二个,第三个困难就用第三个。
今天就不尬码了,我直接按模式来,先看看策略模式的经典类图
策略模式
从类图中我们可以知道,策略模式中主要是三个类:
- Context类:用于装入计谋,类似于我们场景中的锦囊
- Strategy接口:是所有计谋的接口。
- ConcreteStrategy类:具体的计谋,类似于我们场景中三个具体计谋
映射后我们的类图如下,三个计谋继承于计谋接口,锦囊中持有一个计谋,让用户打开。
image.png
编码时刻
先来看IStrategy接口,申明了一个通用的接口,作为计谋的接口方法
public interface IStrategy {
public void operate();
}
接下来看三个计谋,比较简单,各自实现自己的计谋步骤
public class QiaoGuoLaoStrategy implements IStrategy {
@Override
public void operate() {
System.out.println("找乔国老。。。。");
}
}
public class SunFuRenEnemy implements IStrategy {
@Override
public void operate() {
System.out.println("让孙小妹断后。。");
}
}
public class WuGuoTaiStrategy implements IStrategy {
@Override
public void operate() {
System.out.println("找吴国太帮忙。。");
}
}
然后锦囊类,可以将计谋装入,需要使用时就调用operate方法,开启计谋
public class SilkBag {
private IStrategy mStrategy;
public SilkBag(IStrategy strategy) {
this.mStrategy = strategy;
}
public void operate(){
this.mStrategy.operate();
}
}
最后登场的是赵子龙,每次需要就从list中取出一个计谋然后实施,完美解决此场景。
public class ZhaoZiLong {
public static void main(String[] args) {
List<SilkBag> silkBagList = new ArrayList<>();
silkBagList.add(new SilkBag(new QiaoGuoLaoStrategy()));
silkBagList.add(new SilkBag(new WuGuoTaiStrategy()));
silkBagList.add(new SilkBag(new SunFuRenEnemy()));
int i = 1;
for (SilkBag silkBag : silkBagList) {
System.out.println("赵子龙第" + (i++) + "次遇困难,使用锦囊:");
silkBag.operate();
}
}
}
策略模式缺点
上面的代码真的完美么?不完美,因为使用的用户需要知道具体的计谋类。当计谋多的时候,用户就需要知道相应多的类,违背了迪米特法则(最少知识原则),所以我们可以进行相应的封装,这里我使用工厂模式进行简单的封装。
使用简单工厂模式,用于生产锦囊,其实这样更加符合场景的描述,赵云在使用锦囊的时候其实并不知道哪条计谋是第一个,那条计谋是第二个。对于他来说,他只知道我是按顺序来使用,所以传进工厂说我需要第一个计谋,工厂就给了第一个,至于里面是乔国老还是孙小妹的,这个他就不需要关心了。
public class SilkBagFactory {
public static SilkBag getStrategy(int i){
SilkBag silkBag = null;
switch (i){
case 1:
silkBag = new SilkBag(new QiaoGuoLaoStrategy());
break;
case 2:
silkBag = new SilkBag(new WuGuoTaiStrategy());
break;
case 3:
silkBag = new SilkBag(new SunFuRenEnemy());
break;
}
return silkBag;
}
}
再来看看如何调用,代码更加简洁了。
public class ZhaoZiLong {
public static void main(String[] args) {
// List<SilkBag> silkBagList = new ArrayList<>();
// silkBagList.add(new SilkBag(new QiaoGuoLaoStrategy()));
// silkBagList.add(new SilkBag(new WuGuoTaiStrategy()));
// silkBagList.add(new SilkBag(new SunFuRenEnemy()));
//
// int i = 1;
// for (SilkBag silkBag : silkBagList) {
// System.out.println("赵子龙第" + (i++) + "次遇困难,使用锦囊:");
// silkBag.operate();
// }
for (int i = 1; i <= 3; ++i) {
System.out.println("赵子龙第" + i + "次遇困难,使用锦囊:");
SilkBagFactory.getStrategy(i).operate();
}
}
}
写在最后
本篇文章没有长篇大论的讲理论,因为这不是我的风格,更多的是通过前后的代码对比和一些编码时微妙的变化入手,如果这篇文章对你有所启发请给个“❤️”鼓励下吧。
网友评论