策略模式与Spring的碰撞,不错

策略模式是GoF23种设计模式中比较简单的了,也是常用的设计模式之一,今天我们就来看看策略模式。

实际案例
我工作第三年的时候,重构旅游路线的机票查询模块,旅游路线分为四种情况:

如果A地-B地往返都可以直达,那么查询两张机票(往返)
如果A地-B地去程无法直达,需要中转,但是返程可以直达,那么查询三张机票(去程两张,返程一张)
如果A地-B地去程可以直达,但是返程需要中转,那么查询三张机票(去程一张,返程两张)
如果A地-B地往返都无法直达,那么查询四张机票(去程两张,返程两张)
在我重构前,代码差不多是这样的:

    int type = 1;
    // 往返都可以直达
    if (type == 1) {
        // 查询出两张机票
        return;
    }

    // 去程无法直达,需要中转,但是返程可以直达
    if (type == 2) {
        // 查询出三张机票(去程两张,返程一张)
        return;
    }
    // 去程可以直达,但是返程需要中转
    if (type == 3) {
        // 查询出三张机票(去程一张,返程两张)
        return;
    }
    // 往返都无法直达
    else{
        // 查询出四张机票(去程两张,返程两张)
        return;
    }

当时我还是菜鸡(现在也是),也不懂什么设计模式,就是感觉代码都写在一个类中,实在是太长了,不够清爽,不管是哪种类型的线路,最终都是返回机票集合,只是处理逻辑不同,可以提取一个接口出来,再开四个类去实现此接口,最后定义一个Map,Key是Type,Value是接口(实现类),根据Type决定调用哪个实现类,就像下面的酱紫:

public class Ticket {
private String desc;

public Ticket(String desc) {
    this.desc = desc;
}

public String getDesc() {
    return desc;
}

public void setDesc(String desc) {
    this.desc = desc;
}

@Override
public String toString() {
    return "Ticket{" +
            "desc='" + desc + '\'' +
            '}';
}

}
public interface QueryTicketService {
List getTicketList();
}
public class QueryTicketAService implements QueryTicketService {
@Override
public List getTicketList() {
List list = new ArrayList<>();
list.add(new Ticket(“去程机票”));
list.add(new Ticket(“返程机票”));
return list;
}
}
public class QueryTicketBService implements QueryTicketService {
@Override
public List getTicketList() {
List list = new ArrayList<>();
list.add(new Ticket(“去程第一张机票”));
list.add(new Ticket(“去程第二张机票”));
list.add(new Ticket(“返程机票”));
return list;
}
}
public class QueryTicketCService implements QueryTicketService {
@Override
public List getTicketList() {
List list = new ArrayList<>();
list.add(new Ticket(“去程机票”));
list.add(new Ticket(“返程第一张机票”));
list.add(new Ticket(“返程第二张机票”));
return list;
}
}
public class QueryTicketDService implements QueryTicketService {
@Override
public List getTicketList() {
List list = new ArrayList<>();
list.add(new Ticket(“去程第一张机票”));
list.add(new Ticket(“去程第二张机票”));
list.add(new Ticket(“返程第一张机票”));
list.add(new Ticket(“返程第二张机票”));
return list;
}
}
public class Main {
static Map<Integer, QueryTicketService> map = new HashMap<>();

static {
    map.put(1, new QueryTicketAService());
    map.put(2, new QueryTicketBService());
    map.put(3, new QueryTicketCService());
    map.put(4, new QueryTicketDService());
}

public static void main(String[] args) {
    int type = 1;
    System.out.println(map.get(type).getTicketList());
}

}
运行结果:

[Ticket{desc=‘去程机票’}, Ticket{desc=‘返程机票’}]
当初我也不知道什么设计模式,就是感觉这样写完,代码清爽多了,后来才知道这就是策略模式的雏形了。

GoF23种设计模式真正应用广泛的设计模式不多,但是策略模式绝对算其中之一了,你看,当初我都不懂这些,就写出了策略模式的雏形。

原始的策略模式
如果我们遇到类似于上面的需求,第一反应肯定是用if else语句或者switch语句,根据不同的情况执行不同的代码,这样做也没什么大问题,但是我们的项目会越来越复杂,这么做的缺陷就慢慢的显现了出来:如果现在线路新增了一个类型,需要中转两次,就又得加好几个判断的分支(去程中转一次,返程中转两次;去程中转两次,返程中转一次;去程直达,返程中转两次等等),想想就恐怖,这样分支会越来越多,代码会越来越长,越来越难以维护,所以策略模式出现了。

当一个逻辑中,有很多if else语句或者switch语句,而且它们需要解决的问题是一样的,就可以考虑策略模式。

最原始的策略模式有三个角色:

Strategy:抽象策略角色,对算法、策略的抽象,定义每个算法、策略所必需的方法,通常为接口。
ConcreteStrategy:具体策略角色,实现抽象策略角色,完成具体的算法、策略。
Context:上下文环境角色,保存了ConcreteStrategy,负责调用ConcreteStrategy。
而我上面的代码,就有了策略模式的味道,有了Strategy,也有了ConcreteStrategy,缺少的就是Context,如果用最原始的设计模式的写法来实现,是酱紫的:

public class Context {
static Map<Integer, QueryTicketStrategy> map = new HashMap<>();

static {
    map.put(1, new QueryTicketAConcreteStrategy());
    map.put(2, new QueryTicketBConcreteStrategy());
    map.put(3, new QueryTicketCConcreteStrategy());
    map.put(4, new QueryTicketDConcreteStrategy());
}

public void getTicketList(int type) {
    System.out.println(map.get(type).getTicketList());
}

}
public class Main {
public static void main(String[] args) {
Context context = new Context();
context.getTicketList(1);
}
}
运行结果:

[Ticket{desc=‘去程机票’}, Ticket{desc=‘返程机票’}]
在这里,我把类名重新定义了下,让人一眼就可以看出这里使用了策略模式,这也是阿里推荐的命名方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值