Java与设计模式(06)--策略模式

来源:互联网 发布:盼盼食品网络经销商 编辑:程序博客网 时间:2024/06/17 19:12

定义


策略模式(Strategy):它定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法的变化不会影响到使用算法的客户。


角色

  1. Strategy接口:定义了算法的形式;
  2. ConcreteStrategy:实现了具体算法;
  3. Context:对接口中的算法进行实用;
  4. Client:测试类;


实际使用

这里我们可以看个例子:


例子一:

我们有一个这样的类:

package com.freesoft.designpattern.strategy;public class Person {private int id;private String name;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}}

有一天我们想对这个类组成的集合对象进行排序,那么必须要有一个手段能够对这个类的对象进行比较,所以我们这样实现:

package com.freesoft.designpattern.strategy;public class Person implements Comparable<Person> {private int id;private String name;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic int compareTo(Person o) {if (this.getId() != o.getId()) {Integer id1 = Integer.valueOf(this.getId());Integer id2 = Integer.valueOf(o.getId());return  id1.compareTo(id2);} else {String name1 = this.getName();String name2 = o.getName();return name1.compareTo(name2);}}}

通过以上实现,我们能够对Person类型的两个对象实现比较操作,首先比较id,如果id相同那么比较name字段。在集合中我们可以根据这个规则(策略)来对集合进行排序。


问题来了,我们不能保证这个规则/策略就是我们需要的策略。比如,我们可能需要先比较name字段,或者我们可能在某种情况下使用id优先原则,某种情况下使用name优先原则,所以我们的策略是会变化的


考虑到以上问题,我们需要修改我们的代码,我们单独编写一个策略类:

package com.freesoft.designpattern.strategy;import java.util.Comparator;public class PersonComparatorById implements Comparator<Person> {@Overridepublic int compare(Person o1, Person o2) {if (o1.getId() != o2.getId()) {Integer id1 = Integer.valueOf(o1.getId());Integer id2 = Integer.valueOf(o2.getId());return  id1.compareTo(id2);} else {String name1 = o1.getName();String name2 = o2.getName();return name1.compareTo(name2);}}}

并且我们的Person代码变为:


package com.freesoft.designpattern.strategy;import java.util.Comparator;public class Person implements Comparable<Person> {private int id;private String name;private Comparator<Person> c;public Person(int id, String name) {super();this.id = id;this.name = name;}public Comparator<Person> getC() {return c;}public void setC(Comparator<Person> c) {this.c = c;}public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic int compareTo(Person o) {return c.compare(this, o);}}

这样如果我们今后需要使用name优先的比较原则,我们只需要实现一个新类:

package com.freesoft.designpattern.strategy;import java.util.Comparator;public class PersonComparatorByName implements Comparator<Person> {@Overridepublic int compare(Person o1, Person o2) {if (o1.getName().equals(o2.getName())) {Integer id1 = Integer.valueOf(o1.getId());Integer id2 = Integer.valueOf(o2.getId());return  id1.compareTo(id2);} else {String name1 = o1.getName();String name2 = o2.getName();return name1.compareTo(name2);}}}

我们的测试类如下:


package com.freesoft.designpattern.strategy;public class Client {public static void main(String[] args) {Person p1 = new Person(10, "zhangsan");Person p2 = new Person(20, "lisi");PersonComparatorById cId = new PersonComparatorById();PersonComparatorByName cName = new PersonComparatorByName();p1.setC(cId);System.out.println("p1 compara p2 by Id: " + p1.compareTo(p2));p1.setC(cName);System.out.println("p1 compara p2 by Name: " + p1.compareTo(p2));}}



总结

  1. 我们的Comparator接口就是我们抽象的策略;
  2. 我们实现的一个个的PersonComparatorByXXX就是具体的策略;
  3. Person提供了比较的功能,但实际使用时通过setC传入不同的比较策略,所以在实际使用中非常灵活,并且可以独立单元测试、代码维护成本极低。