在实际开发中,我们可能会根据环境或者条件的不同选择不同的算法或者策略去实现该功能。
比如排序、查找。一种常用的方法是硬编码(Hard Coding)在一个类中,如需要提供多种查找算法,可以将这些算法写到一个类中,在该类中提供多个方法,每一个方法对应一个具体的查找算法;当然也可以将这些查找算法封装在一个统一的方法中,通过if…else…或者case等条件判断语句来进行选择。这两种实现方法我们都可以称之为硬编码,如果需要增加一种新的查找算法,需要修改封装算法类的源代码;更换查找算法,也需要修改客户端调用代码。在这个算法类中封装了大量查找算法,该类代码将较复杂,维护较为困难。如果我们将这些策略包含在客户端,这种做法更不可取,将导致客户端程序庞大而且难以维护,如果存在大量可供选择的算法时问题将变得更加严重。
例子1:一个菜单功能能够根据用户的“皮肤”首选项来决定是否采用水平的还是垂直的排列形式。同事可以灵活增加菜单那的显示样式。
例子2:出行旅游:我们可以有几个策略可以考虑:可以骑自行车,汽车,做火车,飞机。每个策略都可以得到相同的结果,但是它们使用了不同的资源。选择策略的依据是费用,时间,使用工具还有每种方式的方便程度 。
1.提出问题:
如何让算法和对象分开,使得算法可以独立于用户而变化?
2.解决问题
策略模式就是为了解决该问题而生。
定义一组算法,将每个算法封装起来,并且可以使得他们之间可以互换。
通过这种方式,可以使得这些算法在用户调用的时候互不影响的变化。
该模式本身把对象和算法区分开来,功能非常强大,同时也体现了面向对象设计的原则:封装变化的概念&编程中使用接口而非对接口的实现。
3.策略模式的组成
抽象策略角色:策略类,通常由一个接口或者抽象类实现
具体策略角色:包装了相关的算法和行为,需要实现策略类接口或者继承策略类的抽象类
环境角色:持有一个策略类的引用,最终给客户端调用的
4.策略模式的实现
a).定义一个抽象类或者接口作为策略类,其中声明该策略类要实现的功能,比如排序
b).针对一组算法(多种排序算法),将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以互相替换,即具体策略类的实现
c).定义环境类,该类需实现策略类接口或继承策略类,负责维持策略类和使用策略类,各种具体的算法在具体的策略中提供。由于算法和环境独立开来,算法的修改都不会影响环境和客户端
5.策略模式的编写步骤
1). 对策略对象定义一个公共接口
2). 编写策略类,该类需实现上述的公共接口
3). 编写环境类,在该类中保存一个对策略对象的引用
4). 在使用策略对象的类中,即环境类,实现对策略对象的set和get方法或者使用构造方法完成赋值
6.手动实现自己的策略模式
定义一个People类,其中有成员变量id,name,age,使用策略模式实现按上述三个属性的升序和降序排列,如果name或者age相同,则根据id的升序排列。输出打印结果。
定义People类
public class People {
private static int ID = 1001;
private int id;
private String name;
private int age;
public People(){
id = ID++;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
编写策略接口SortInterface.java
public interface SortInterface {
public void sort(List<People> list);
}
编写策略类,依次是按照id升序,id降序,age升序,age降序,name升序,name降序的策略类实现
public class UpSortById implements SortInterface,Comparator<People> {
@Override
public void sort(List<People> list) {
Collections.sort(list,this);
}
@Override
public int compare(People o1, People o2) {
return o1.getId() - o2.getId();
}
}
public class DownSortById implements SortInterface,Comparator<People> {
@Override
public void sort(List<People> list) {
//sort(List<T> list, Comparator<? super T> c) 根据指定比较器产生的顺序对指定列表进行排序
//DownSortById类实现了Comparator接口,是一个比较器。this表示指向该对象的引用,传进this即可,不需要再new一个DownSortById对象
Collections.sort(list,this);
}
@Override
public int compare(People o1, People o2) {
return o2.getId() - o1.getId();
}
}
public class UpSortByAge implements SortInterface,Comparator<People> {
@Override
public void sort(List<People> list) {
Collections.sort(list,this);
}
@Override
public int compare(People o1, People o2) {
int result = o1.getAge() - o2.getAge();
if(0 == result){
return o1.getId() - o2.getId();
}
return result;
}
}
public class DownSortByAge implements SortInterface,Comparator<People> {
@Override
public void sort(List<People> list) {
Collections.sort(list,this);
}
@Override
public int compare(People o1, People o2) {
int result = o2.getId() - o1.getId();
if(0 == result){
return o1.getId() - o2.getId();
}
return result;
}
}
public class UpSortInterfaceByName implements SortInterface,Comparator<People> {
@Override
public void sort(List<People> list) {
Collections.sort(list,this);
}
@Override
public int compare(People o1, People o2) {
int result = o1.getName().compareTo(o2.getName());
if(0 == result){
return o1.getId() - o2.getId();
}
return result;
}
}
public class DownSortInterfaceByName implements SortInterface,Comparator<People> {
@Override
public void sort(List<People> list) {
Collections.sort(list,this);
}
@Override
public int compare(People o1, People o2) {
int result = o2.getName().compareTo(o1.getName());
if(0 == result){
return o1.getId() - o2.getId();
}
return result;
}
}
编写环境类
public class Environment {
//维护策略接口的引用
private SortInterface sortInterface;
//通过构造方法设置策略
public Environment(SortInterface sortInterface){
this.sortInterface = sortInterface;
}
public Environment(){}
//通过set方法设置策略
public void setSortInterface(SortInterface sortInterface) {
this.sortInterface = sortInterface;
}
public void sort(List<People> list){
this.sortInterface.sort(list);
}
}
编写main函数作为客户端使用:
public class Main {
public static void main(String[] args){
People p1 = new People();
p1.setAge(10);
p1.setName("ACC");
People p2 = new People();
p2.setName("ABC");
p2.setAge(30);
People p3 = new People();
p3.setAge(15);
p3.setName("xyz");
People p4 = new People();
p4.setName("Maria");
p4.setAge(15);
People p5 = new People();
p5.setName("ABC");
p5.setAge(20);
List<People> list = new ArrayList<People>();
list.add(p1);
list.add(p2);
list.add(p3);
list.add(p4);
list.add(p5);
UpSortInterfaceByName usn = new UpSortInterfaceByName();
Environment env = new Environment();
System.out.println("-----------------按照名字的升序排序--------------------");
env.setSortInterface(usn);
env.sort(list);
for(People p : list){
System.out.println(p.getId()+","+p.getName()+","+p.getAge());
}
System.out.println("-------------------按照id的降序排列---------------------");
DownSortById dsi = new DownSortById();
env.setSortInterface(dsi);
env.sort(list);
for(People p : list){
System.out.println(p.getId()+","+p.getName()+","+p.getAge());
}
System.out.println("-----------------按照年龄的升序排列----------------------");
}
}
7.策略模式的缺点
1).客户端必须知道所有的策略类,并自行决定使用哪一个策略类
2).造成有很多策略类
8.策略模式的意义
——使得开发人员能够开发出由许多可替换的部分组成的软件,并且各个部分之间是弱连接的关系
——弱连接的特性使得软件有更强的可扩展性,易于维护;大大提高了软件的可重用性
9.JDK Collections类就使用了策略模式