在现实生活中常常遇到实现某种目标存在多种策略可供选择的情况,例如,出行旅游可以乘坐飞机、乘坐火车、骑自行车或自己开私家车等。在软件开发中也常常遇到类似的情况,当实现某一个功能存在多种算法或者策略,我们可以根据环境或者条件的不同选择不同的算法或者策略来完成该功能,如数据排序策略有冒泡排序、选择排序、插入排序、二叉树排序等。

# 一、策略模式基本介绍

【1】策略模式(Strategy Pattern)中,定义算法族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立于使用算法的用户。策略模式属于对象行为模式,它通过对算法进行封装,把使用算法的责任和算法的实现分割开来,并委派给不同对象进行管理。
【2】这算法体现了几个设计原则,第一:把变化的代码从不变的代码中分离出来;第二:针对接口编程而不是具体的类(定义了策略接口);第三:多个组合/聚合,少用继承(客户通过组合方式使用策略)
【3】多重条件语句不易维护,而使用策略模式可以避免使用多重条件查询。算法可以自由切换。
【4】策略模式提供了对 “开闭原则” 的完美支持,可以在不修改原代码的情况下,灵活增加新算法。
【5】策略模式把算法的使用放到环境类中,而算法的实现移到具体策略类中,实现了二者的分离。
【6】缺点:客户端必须理解所有策略算法的区别,以便适时选择恰当的算法类。同时策略模式造成很多的策略类。

# 二、策略模式结构类图

TIP

策略模式是准备一组算法,并将这组算法封装到一系列的策略类里面,作为一个抽象策略类的子类。策略模式的重心不是如何实现算法,而是如何组织这些算法,从而让程序结构更加灵活,具有更好的维护性和扩展性。

策略模式的主要角色如下: 抽象策略(Strategy)类:定义一个公共接口,各种不同的算法以不同的方式实现这个接口,一般使用接口或者抽象类。
具体策略(Concrete Strategy)类: 实现了抽象策略定义的接口,提供具体的算法实现。
上下文(Context)类: 持有一个具体的策略类引用,最终给客户端调用。

访问者模式

# 三、策略模式案例分析

我们通过写一个旅游出行方式的案例来体会策略模式的特点:

【1】交通方式的抽象策略角色

//交通方式的 抽象策略
public interface TripMode {
    public void goOut();
}
1
2
3
4

【2】具体策略角色(火车、汽车、飞机)

//具体实现类一 : 飞机
public class ByCar implements TripMode{
 
    @Override
    public void goOut() {
        System.out.println("飞机出行,最快的选择");
    }
}
//具体实现类二 : 火车
public class ByTrain implements TripMode{
 
    @Override
    public void goOut() {
        System.out.println("火车出行,最安全的选择");
    }
}
//具体实现类三 : 自驾车
public class SelfDrive implements TripMode{
 
    @Override
    public void goOut() {
        System.out.println("旅游就的是自驾车");
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

【3】我们就举一个最安全的出行实例:组合抽象策略类,实现了具体使用类与策略类的分离。

package stratege;
//注重安全的人,都会选择火车
public class Safe {
    //组合接口
    private TripMode train;
 
    public Safe() {
        //组合一个火车实例
        train = new ByTrain();
    }
 
    //客户端也可以根据情况进行重新赋值
    public void setTrain(TripMode train) {
        this.train = train;
    }
 
    public void toBeijing() {
        //去北京选择的工具
        train.goOut();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

【4】客户端直接调用即可,或者使用 set 对其策略进行重置。

public class Client {
    public static void main(String[] args) {
        Safe safe = new Safe();
        //火车出行,最安全的选择
        safe.toBeijing();
    }
}
1
2
3
4
5
6
7

# 四、策略接口的源码应用分析

【1】抽象策略类:Comparator 接口

public interface Comparator<T> {
    ...
    int compare(T o1, T o2);
    ...
}
1
2
3
4
5

【2】具体策略类:可以根据自己的需求,实现不同的升序和降序等策略。

public static void main(String[] args) {
    Integer[] data = {3,1,5,8,6};
    //实现升序排序,返回-1放左边,1放右边,0不变
    //Comparator 就是一个抽象策略类(接口),我们对其进行实现,就是一个具体的策略
    Comparator<Integer> comparator = new Comparator<Integer>() {
        @Override
        public int compare(Integer o1, Integer o2) {
            if(o1>o2) {
                return 1;
            }else {
                return -1;
            }
        }
    };
    Arrays.sort(data,comparator);
    //[1, 3, 5, 6, 8]
    System.out.println(Arrays.toString(data));
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
(adsbygoogle = window.adsbygoogle || []).push({});