简介:
定义算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户端。它首先定义不同的算法策略,然后客户端把算法策略作为它的一个参数。使用这种模式的一个不错的例子是Collection.sort()方法了,它使用Comparator对象作为参数。根据Comparator接口不同实现,对象会被不同的方法排序。
角色:
环境(Context):用来操作策略的上下文环境,屏蔽高层模块(客户端)对策略,算法的直接访问,封装可能存在的变化;
抽象策略角色(Strategy):定义了一个公共接口,各种不同的算法以不同的方式实现这个接口,环境角色使用这个接口调用不同的算法,一般使用接口或抽象类实现
具体策略角色(ConcreteStrategy):实现了抽象策略定义的接口,提供具体的算法实现。
原则:
1、找出应用中可能需要变化之处,把他们独立出来。
2、针对接口编程,而不是针对实现
3、多用组合,少用继承
一般使用场景:
当系统能在几种算法中快速地切换,或系统中有一些类,它们仅行为不同时,或系统中存在多重条件选择语句时,可以考虑采用策略模式。
优缺点:
优点:
1、算法可以自由切换
2、避免使用多重条件判断
3、扩展性良好
缺点:
策略类数量增多,所有的策略类都需要对外暴露(不过可以通过其他如工厂方法模式修复这个缺陷)
JDK示例:
java.util.Collections方法:
sort(List<T> list, Comparator<? super T> c)
参数:
list - 要排序的列表。
c - 确定列表顺序的比较器。null 值指示应该使用元素的 自然顺序。
根据指定Comparator产生的顺序对指定列表进行排序。此列表内的所有元素都必须能够使用指定Comparator相互比较。sort()方法是常用的策略设计模式示例之一,它以Comparator作为参数,我们可以为Comparator接口提供不同的实现。现在,Collections.sort()方法将根据传递给它的比较器实现对象排序。比如根据体重或大小来对Employee进行排序,您可以简单地创建一个Comparator来实现。
我们先来看下可与之对比的Comparable接口, 它为类的对象定义了默认顺序。这种默认顺序也称为对象的自然顺序。
class Employee implements Comparable<Employee> {
private int id;
private String name;
private double salary;
private LocalDate joiningDate;
public Employee(int id, String name, double salary, LocalDate joiningDate) {
this.id = id;
this.name = name;
this.salary = salary;
this.joiningDate = joiningDate;
}
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;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public LocalDate getJoiningDate() {
return joiningDate;
}
public void setJoiningDate(LocalDate joiningDate) {
this.joiningDate = joiningDate;
}
// 根据ID进行比较
/**
\* @param anotherEmployee - The Employee to be compared.
\* @return A negative integer, zero, or a positive integer as this employee
\* is less than, equal to, or greater than the supplied employee object.
*/
@Override
public int compareTo(Employee anotherEmployee) {
return this.getId() - anotherEmployee.getId();
}
// Two employees are equal if their IDs are equal
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Employee employee = (Employee) o;
return id == employee.id;
}
@Override
public int hashCode() {
return Objects.hash(id);
}
@Override
public String toString() {
return "Employee{" +
"id=" + id +
", name='" + name + '\'' +
", salary=" + salary +
", joiningDate=" + joiningDate +
'}';
}
}
但是,如果您因为某个需求更改默认顺序呢?例如,如果您想根据前面示例中的Employee对象的名称而不是id对其进行排序,该怎么办?
你不能更改compareTo()函数的实现,因为不单单是你那块的特定需求, 它会影响所有地方的顺序。
此外,如果您正在处理预定义的Java类或在第三方库中定义的类,则无法更改默认顺序。例如,字符串对象的默认顺序是按字母顺序排列。但是如果你想根据它们的长度来排序呢?
对于这种情况,Java提供的正是Comparator接口。您可以定义一个Comparator并将其传递给像Collections.sort() 或 Arrays.sort()的排序函数。根据Comparator定义的顺序对对象排序。
public interface Comparator<T> {
int compare(T o1, T o2);
}
public class ComparatorExample {
public static void main(String[] args) {
List<Employee> employees = new ArrayList<>();
employees.add(new Employee(1010, "Rajeev", 100000.00, LocalDate.of(2010, 7, 10)));
employees.add(new Employee(1004, "Chris", 95000.50, LocalDate.of(2017, 3, 19)));
employees.add(new Employee(1015, "David", 134000.00, LocalDate.of(2017, 9, 28)));
employees.add(new Employee(1009, "Steve", 100000.00, LocalDate.of(2016, 5, 18)));
System.out.println("Employees : " + employees);
// 根据名称排序
Comparator<Employee> employeeNameComparator = new Comparator<Employee>() {
@Override
public int compare(Employee e1, Employee e2) {
return e1.getName().compareTo(e2.getName());
}
};
/*
上面的Comparator可以用如下的lambda表达式写 =>
employeeNameComparator = (e1, e2) -> e1.getName().compareTo(e2.getName());
Java 8 Comparator默认方法甚至可以写的更简单
employeeNameComparator = [Comparator.comparing(Employee::getName](http://Comparator.comparing(Employee::getName))
*/
Collections.sort(employees, employeeNameComparator);
System.out.println("\nEmployees (Sorted by Name) : " + employees);
// 根据收入排序
Comparator<Employee> employeeSalaryComparator = new Comparator<Employee>() {
@Override
public int compare(Employee e1, Employee e2) {
if(e1.getSalary() < e2.getSalary()) {
return -1;
} else if (e1.getSalary() > e2.getSalary()) {
return 1;
} else {
return 0;
}
}
};
Collections.sort(employees, employeeSalaryComparator);
System.out.println("\nEmployees (Sorted by Salary) : " + employees);
//根据入职时间排序
Comparator<Employee> employeeJoiningDateComparator = new Comparator<Employee>() {
@Override
public int compare(Employee e1, Employee e2) {
return e1.getJoiningDate().compareTo(e2.getJoiningDate());
}
};
Collections.sort(employees, employeeJoiningDateComparator);
System.out.println("\nEmployees (Sorted by JoiningDate) : " + employees);
}
}
与状态模式区别