设计模式02-策略模式Strategy
一上来直接聊策略模式我相信大部分没有接触过的人一定是一头雾水的,我们先从一个数组排序的例子慢慢深入。
一、数组排序
-
首先我们先将 int 数组排序。
Main.java
public class Main { public static void main(String[] args) { //1、指定类型比较 int int[] a = {3,6,3,1,8,10}; Sorter.sort(a); System.out.println(Arrays.toString(a)); }
Sorter.java
这里排序我们就使用最简单的选择排序,如果不太会的可以看我之前对于排序的博客。不过挖的坑还没填完。应该也不会有人催的。
public class Sorter {
//指定类型比较 int
public static void sort(int[] arr) {
for (int i = 0; i < arr.length - 1; i++) {
int minPos = i;
for (int j = i + 1; j < arr.length; j++) {
minPos = arr[j] < arr[minPos] ? j : minPos;
}
swap(arr, i, minPos);
}
}
private static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
非常简单,排序肯定是没有问题的。
- 下面定义一个对象 Cat 小猫咪,来对Cat进行排序。这里我们定义喵咪有两个属性,一个重量,一个高度。还需要定义一个compareTo方法来进行比较,就哪个猫比谁胖吧。
Cat.java
public class Cat {
private Integer weight;
private Integer height;
public int compareTo(Cat c) {
if (this.weight < c.weight) {
return -1;
} else if (this.weight > c.weight) {
return 1;
} else {
return 0;
}
}
public Cat(Integer weight, Integer height) {
this.weight = weight;
this.height = height;
}
@Override
public String toString() {
return "Cat{" +
"weight=" + weight +
", height=" + height +
'}';
}
public Integer getWeight() {
return weight;
}
public void setWeight(Integer weight) {
this.weight = weight;
}
public Integer getHeight() {
return height;
}
public void setHeight(Integer height) {
this.height = height;
}
}
Sorter.java
public class Sorter {
public static void sort(Cat[] arr) {
for (int i = 0; i < arr.length - 1; i++) {
int minPos = i;
for (int j = i + 1; j < arr.length; j++) {
minPos = arr[j].compareTo(arr[minPos]) == -1 ? j : minPos;
}
swap(arr, i, minPos);
}
}
private static void swap(Cat[] arr, int i, int j) {
Cat temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
Main.java
public class Main {
public static void main(String[] args) {
//2、对象类型比较 Cat
//对象 定义compareTo方法
Cat[] a = {new Cat(5, 5), new Cat(1, 1), new Cat(3, 3)};
Sorter.sort(a);
System.out.println(Arrays.toString(a));
}
}
也很简单,胖胖的猫排在后面。
-
接下来我们再定义狗子 Dog 这个对象,对他进行比较。这次我不想每次做比较都要修改Sorter,我自己定义一个接口MyComparable,让需要比较的对象去实现这个接口。用狗子的重量来进行比较。
MyComparable.java
public interface MyComparable<T> { Integer compareTo(T t); }
Dog.java
public class Dog implements MyComparable<Dog>{ private Integer weight; private Integer height; public Integer compareTo(Dog d) { if (this.weight < d.weight) { return -1; } else if (this.weight > d.weight) { return 1; } else { return 0; } } public Dog(Integer weight, Integer height) { this.weight = weight; this.height = height; } @Override public String toString() { return "Cat{" + "weight=" + weight + ", height=" + height + '}'; } public Integer getWeight() { return weight; } public void setWeight(Integer weight) { this.weight = weight; } public Integer getHeight() { return height; } public void setHeight(Integer height) { this.height = height; } }
Sorter.java
public class Sorter { public static void sort(MyComparable[] arr) { for (int i = 0; i < arr.length - 1; i++) { int minPos = i; for (int j = i + 1; j < arr.length; j++) { minPos = arr[j].compareTo(arr[minPos]) == -1 ? j : minPos; } swap(arr, i, minPos); } } private static void swap(MyComparable[] arr, int i, int j) { MyComparable temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } }
Main.java
public class Main { public static void main(String[] args) { //3、对Object对象 进行比较但是没有compareTo方法 // -->使用MyComparable接口 实现compareTo方法 Dog[] a = {new Dog(5, 5), new Dog(1, 1), new Dog(3, 3)}; Sorter.sort(a); System.out.println(Arrays.toString(a)); } }
-
如果我们需要给狗子用高度进行比较,或者是去自定义更多的比较方法。那么我们不能把比较的方法放到Dog的类里面了。我们可以使用比较器,定义不同的排序。
Main.java
public class Main {
public static void main(String[] args) {
//4、通过比较器 排序的同时传入排序策略
//使用Comparable接口 只能定义一种实现,但是使用Comparator就可以定义多种不同类型的排序
Dog[] a = {new Dog(5, 5), new Dog(1, 1), new Dog(3, 3)};
Sorter<Dog> dogSorter = new Sorter<>();
//通过lamda表达式的写法,不过用定义类DogWeightComparator的方法更清楚一点。
/*dogSorter.sort(a, (o1, o2) -> {
if (o1.getWeight() > o2.getWeight()) {
return 1;
} else if (o1.getWeight() < o2.getWeight()) {
return -1;
} else {
return 0;
}
});*/
// dogSorter.sort(a,new DogWeightComparator());
dogSorter.sort(a,new DogHeightComparator());
System.out.println(Arrays.toString(a));
}
}
Comparator.java
public interface Comparator<T> {
int compare(T o1,T o2);
}
DogHeightComparator.java 狗子高度比较器
public class DogHeightComparator implements Comparator<Dog>{
@Override
public int compare(Dog o1, Dog o2) {
if (o1.getHeight() > o2.getHeight()) {
return 1;
} else if (o1.getHeight() < o2.getHeight()) {
return -1;
} else {
return 0;
}
}
}
DogWeightComparator.java 狗子重量比较器
public class DogWeightComparator implements Comparator<Dog>{
@Override
public int compare(Dog o1, Dog o2) {
if (o1.getWeight() > o2.getWeight()) {
return 1;
} else if (o1.getWeight() < o2.getWeight()) {
return -1;
} else {
return 0;
}
}
}
Sorter.java
public class Sorter<T> {
public void sort(T[] arr, Comparator<T> comparator) {
for (int i = 0; i < arr.length - 1; i++) {
int minPos = i;
for (int j = i + 1; j < arr.length; j++) {
minPos = comparator.compare(arr[j], arr[minPos]) == -1 ? j : minPos;
}
swap(arr, i, minPos);
}
}
private void swap(T[] arr, int i, int j) {
T temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
我们通过实现Comparator接口的方式去定义各种各样的比较器。
策略模式把不同的排序方式封装起来。对修改封闭,对扩展开放的开闭原则。
二、策略模式
百度百科:
策略模式是指有一定行动内容的相对稳定的策略名称。策略模式在古代中又称“计策”,简称“计”,如《汉书·高帝纪上》:“汉王从其计”。这里的“计”指的就是计谋、策略。策略模式具有相对稳定的形式,如“避实就虚”、“出奇制胜”等。一定的策略模式,既可应用于战略决策,也可应用于战术决策;既可实施于大系统的全局性行动,也可实施于大系统的局部性行动。
大白话:
策略模式就是做意见是的不同方法,我们给他封装起来。我们需要用哪个就把哪个传进去。
三、项目应用
比如说我们有这样一个支付的需求,可以是支付宝也可以是现金。
第一步 创建订单实体类 Order,用来传递订单信息
public class Order {
private String orderId;
private String username;
private Integer money;
public Order() {
}
public Order(String orderId, String username, Integer money) {
this.orderId = orderId;
this.username = username;
this.money = money;
}
public String getOrderId() {
return orderId;
}
public void setOrderId(String orderId) {
this.orderId = orderId;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public Integer getMoney() {
return money;
}
public void setMoney(Integer money) {
this.money = money;
}
}
第二步 创建支付方式接口 Payment 通过订单进行支付
public interface Payment {
void pay(Order order);
}
第三步 创建实现接口的实体类 ALiPay 和 RMBPay
public class ALiPay implements Payment {
@Override
public void pay(Order order) {
System.out.println("订单号:" + order.getOrderId() + "通过支付宝发给" + order.getUsername() + order.getMoney() + "元");
}
}
public class RMBPay implements Payment {
@Override
public void pay(Order order) {
System.out.println("订单号:" + order.getOrderId() + "通过现金发给" + order.getUsername() + order.getMoney() + "元");
}
}
第四步 创建Context类 PayContext
public class PayContext {
private Payment payment;
void pay(Order order) {
payment.pay(order);
}
public void setPayment(Payment payment) {
this.payment = payment;
}
public PayContext() {
}
public PayContext(Payment payment) {
this.payment = payment;
}
}
第五步 定义枚举类PayType 通过PayType来调用
public enum PayType {
RMBPAY(new RMBPay()),
ALIPAY(new ALiPay()),
;
private Payment payment;
PayType(Payment payment) {
this.payment = payment;
}
public Payment getPayment() {
return payment;
}
}
第六步 测试 使用 PayContext 来查看当它改变策略 Payment 时的行为变化。
public class Test {
public static void main(String[] args) {
PayContext aLiContext = new PayContext();
PayContext rMBContext = new PayContext();
aLiContext.setPayment(PayType.ALIPAY.getPayment());
rMBContext.setPayment(PayType.RMBPAY.getPayment());
aLiContext.pay(new Order("pay001","zhow",500));
rMBContext.pay(new Order("pay002","jy",200));
}
}
第七步 输出结果
订单号:pay001通过支付宝发给zhow500元
订单号:pay002通过现金发给jy200元
结论
这样我们遵循了开闭原则,对修改关闭,对扩展开放。如果要再加一个微信支付的话,只需要加入实现payment接口就行。