序言
都毕业好几年了,对于设计模式,平时也偶尔接触过,但却没有系统的学习过,自然在遇到问题找解决方案的时候,也很少能想到设计模式,感觉总是一种模糊的状态,所以,准备重写梳理一下。
注:本系列设计模式相关代码,开发语言使用Java,JDK版本基于1.8。
概述
策略模式是属于一种行为型的设计模式,针对的是算法。我们可以通俗的理解为,策略模式就是对某一行为,能根据不同的实现,完成相同的功能。比如排序,我们能根据不同的类型,调用不同的实现,来实现相同的功能,就是排序。
实现
策略模式中涉及到三个角色:
- Context角色:持有一个Strategy角色的引用;
- Strategy(抽象策略)角色:该角色通常是接口或抽象类;
- ConcreteStrategy(具体策略)角色:实现了抽象策略角色的算法。
实例
我们拿一个例子来加深对策略模式的了解。比如大家出去旅游,可以选择开火车,也可以选择骑自行车,也可以选择做汽车。这其实就是一种策略模式的应用。
Strategy角色
public interface Strategy {
void travel();
}
抽象角色,只有一个方法,就是出行的方法。
ConcreteStrategy具体策略
选择坐汽车出去玩:
public class CarStrategy implements Strategy{
@Override
public void travel() {
System.out.println("--做汽车出去玩--");
}
}
选择骑自行车出去玩:
public class BikeStrategy implements Strategy{
@Override
public void travel() {
System.out.println("--骑自行车出去玩--");
}
}
选择坐火车出去玩:
public class TrainStrategy implements Strategy{
@Override
public void travel() {
System.out.println("--坐火车出去玩--");
}
}
Context角色
出去玩的对象是人:
public class PersonContext {
private Strategy strategy;
public PersonContext(Strategy strategy) {
this.strategy = strategy;
}
public void travel() {
strategy.travel();
}
}
ClientTest
public class ClientTest {
public static void main(String[] args) {
PersonContext personContext = new PersonContext(new BikeStrategy());
personContext.travel();
personContext = new PersonContext(new TrainStrategy());
personContext.travel();
}
}
打印结果:
--骑自行车出去玩--
--坐火车出去玩--
这时候如果说,这时候出行的方式要改为坐轮船,其实这就相当于更改策略,那我们再实现一个类,然后再调用的时候想办法把参数传进去就可以了。
有一点,这里使用构造方法传参数并不是必须的,当然我们可以通过其他方式传递参数,只需要把参数传递过去即可。
其实从上面代码中我们可以分析得到:
- 策略模式就是对于同一行为(出行),通过不同的实现(汽车,火车,自行车),达到相同的目的。
- 策略模式的侧重点就是在行为上,所以要对行为进行抽象,所以很适合用接口来表示。
- 很多时候,策略的实现可以通过匿名内部类或者Lambda表达式的形式来实现,比如Collections的sort方法;
既然说道了Collections的sort方法,我们再以Collections的sort方法来举一个例子,比如我们要对自定义对象进行排序:
自定义对象Person,我们要根据其中的属性进行排序:
public class Person {
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"age=" + age +
'}';
}
}
自定义比较器PersonComparator:
public class PersonComparator implements Comparator<Person>{
@Override
public int compare(Person o1, Person o2) {
return o1.getAge() - o2.getAge();
}
}
进行测试:
public class ComparatorTest {
public static void main(String[] args) {
List<Person> list = getPersonList();
Collections.sort(list, new PersonComparator());
System.out.println(list);
}
public static List<Person> getPersonList() {
Person person1 = new Person();
person1.setAge(10);
Person person2 = new Person();
person2.setAge(15);
Person person3 = new Person();
person3.setAge(12);
List<Person> list = new ArrayList<>();
list.add(person1);
list.add(person2);
list.add(person3);
return list;
}
}
打印结果:
[Person{age=10}, Person{age=12}, Person{age=15}]
当然,这种情况我们也可以使用匿名类来实现该功能:
public static void main(String[] args) {
List<Person> list = getPersonList();
Collections.sort(list, new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
return o1.getAge() - o2.getAge();
}
});
System.out.println(list);
}
然后我们也可以使用Lambda表达式来实现:
Collections.sort(list, (o1, o2) -> o1.getAge() - o2.getAge());
再然后,我们还可以使用JDK8中中Comparator里的comparingInt来实现:
Collections.sort(list, Comparator.comparingInt(Person::getAge));
从上面就可以看出来,Collections.sort方法就是策略模式的一种很好的诠释。这里的Comparator就相当于Strategy角色,而Collections则具备了Context的角色。
总结
- 策略模式,就是对于同一行为,通过不同的实现,完成相同的功能。策略模式封装的是一种变化的状态。所以说当我们有类似的,需要针对不同的情况实现不同的规则的时候,不妨考虑使用下策略模式。
- 很多时候策略类可以使用匿名类或JDK8之后的Lambda表达式来实现,从而避免实现太多的类;
- 使用策略模式的时候还会有一个问题,因为策略模式中算法的选择是由客户端决定的,所以策略模式在使用的时候客户端必须要知道所有的策略类,明白不同的策略类处理哪些不同的功能。然后根据需要决定使用哪一个策略类。
本文参考自:
深入理解Arrays.sort()
策略设计模式使用
《大话设计模式》