strategy_策略模式-1
写一个排序类Sorter,写一个比较int类型方法;如果需要实现double类型的比较,就再写个double类型的方法;如果需要实现float类型的比较,就再写一个float类型的方法。
数值类型的很好比较,直接比较数值大小就可以了。
那么,如果想要比较自定义的类Cat,要怎么比较呢?重写排序方法,把int类型改成Cat类型?直接改是不行的,那就给Cat类提供一个比较的方法。
排序类 Sorter.java
package org.garen.strategy;
/**
* 排序
*/
public class Sorter {
/**
* int类型排序
* @param arr 数组
*/
public static void sort(int[] arr) {
for (int i = 0; i < arr.length; i++) {
int minPos = i;
for (int j = i+1; j < arr.length; j++) {
minPos = arr[j] < arr[minPos] ? j : minPos;
}
swap(arr, i, minPos);
}
}
// double、float类型,把int替换一下就可以了,这里省略。。。
/**
* Cat类型排序
* @param arr 数组
*/
public static void sort(Cat[] arr) {
for (int i = 0; i < arr.length; 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);
}
}
/**
* 交换位置
* @param arr int数组
* @param i 数组下标
* @param j 数组下标
*/
static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
/**
* 交换位置
* @param arr Cat数组
* @param i 数组下标
* @param j 数组下标
*/
static void swap(Cat[] arr, int i, int j) {
Cat temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
猫类Cat.java
package org.garen.strategy;
/**
* 猫
*/
public class Cat {
int weight, height; // 体重,身高
/**
* 构造函数
* @param weight 体重
* @param height 身高
*/
public Cat(int weight, int height) {
this.weight = weight;
this.height = height;
}
/**
* 比较猫的大小
* @param c 猫
* @return 比较结果
*/
public int compareTo(Cat c) {
if(this.weight < c.weight) return -1;
else if(this.weight > c.weight) return 1;
else return 0;
}
@Override
public String toString() {
return "Cat{" +
"weight=" + weight +
", height=" + height +
'}';
}
}
测试类Main.java
package org.garen.strategy;
import java.util.Arrays;
/**
* 测试类
*/
public class Main {
public static void main(String[] args) {
// int数组排序
int[] a = {9, 2, 3, 5, 7, 1, 4};
Sorter.sort(a);
System.out.println(Arrays.toString(a));
// Cat数组排序
Cat[] b = {new Cat(5, 5), new Cat(3, 3), new Cat(1, 1)};
Sorter.sort(b);
System.out.println(Arrays.toString(b));
}
}
运行结果:
[1, 2, 3, 4, 5, 7, 9]
[Cat{weight=1, height=1}, Cat{weight=3, height=3}, Cat{weight=5, height=5}]
strategy_策略模式-2
前面我们为了比较猫的大小,在Sorter类中写了比较猫的重载方法。那么我还需要比较狗,比较树,比较程序员,比较其它对象,那么每次都要在Sorter类中重载方法吗?
如果这个Sorter是JDK提供的,那每次程序员需要比较新的对象,都要联系Oracle公司,让他们的程序员帮忙在Sorter类中重载我们对象的比较方法吗?
开个玩笑,这肯定不可能的。
我们可以这样实现:Sorter中只提供一个sort方法,参数是Comparable,哪个类需要用这个sort方法,自己实现Comparable接口的compareTo方法就可以了。简单讲,哪个类需要用sort方法,哪个类自己提供一个比较的方法。
排序类 Sorter.java
package org.garen.strategy;
/**
* 排序
*/
public class Sorter {
/**
* Cat类型排序
* @param arr 数组
*/
public static void sort(Comparable[] arr) {
for (int i = 0; i < arr.length; 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);
}
}
/**
* 交换位置
* @param arr Cat数组
* @param i 数组下标
* @param j 数组下标
*/
static void swap(Comparable[] arr, int i, int j) {
Comparable temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
猫类Cat.java
package org.garen.strategy;
/**
* 猫
*/
public class Cat implements Comparable<Cat>{
int weight, height; // 体重,身高
/**
* 构造函数
* @param weight 体重
* @param height 身高
*/
public Cat(int weight, int height) {
this.weight = weight;
this.height = height;
}
/**
* 实现Comparable接口,必须要重写compareTo方法
* 比较猫的大小
* @param c 猫
* @return 比较结果
*/
@Override
public int compareTo(Cat c) {
if(this.weight < c.weight) return -1;
else if(this.weight > c.weight) return 1;
else return 0;
}
@Override
public String toString() {
return "Cat{" +
"weight=" + weight +
", height=" + height +
'}';
}
}
狗类Dog.java
package org.garen.strategy;
/**
* 狗
*/
public class Dog implements Comparable<Dog> {
private int food; // 饭量
public Dog(int food) {
this.food = food;
}
@Override
public int compareTo(Dog d) {
if(this.food < d.food) return -1;
else if(this.food > d.food) return 1;
else return 0;
}
@Override
public String toString() {
return "Dog{" +
"food=" + food +
'}';
}
}
测试类Main.java
package org.garen.strategy;
import java.util.Arrays;
/**
* 测试类
*/
public class Main {
public static void main(String[] args) {
// int数组排序
Integer[] a = {9, 2, 3, 5, 7, 1, 4};
Sorter.sort(a);
System.out.println(Arrays.toString(a));
// Cat数组排序
Cat[] b = {new Cat(5, 5), new Cat(3, 3), new Cat(1, 1)};
Sorter.sort(b);
System.out.println(Arrays.toString(b));
// Dog数组排序
Dog[] c = {new Dog(3), new Dog(5), new Dog(2)};
Sorter.sort(c);
System.out.println(Arrays.toString(c));
}
}
[1, 2, 3, 4, 5, 7, 9]
[Cat{weight=1, height=1}, Cat{weight=3, height=3}, Cat{weight=5, height=5}]
[Dog{food=2}, Dog{food=3}, Dog{food=5}]
strategy_策略模式-3
前面只是进行铺垫,还没有真正用到策略模式。下面的例子开始用策略模式了。
我们定义一个比较器接口,该接口必须要实现compareTo方法。排序方法改成传入泛型数组和一个比较器。这样,同一个对象数组,传入不同比较器就可以按照不同的策略对数组进行排序。这样就是在使用策略模式了。
实体类
Cat.java
package org.garen.strategy;
/**
* 猫
*/
public class Cat{
int weight, height; // 体重,身高
/**
* 构造函数
* @param weight 体重
* @param height 身高
*/
public Cat(int weight, int height) {
this.weight = weight;
this.height = height;
}
@Override
public String toString() {
return "Cat{" +
"weight=" + weight +
", height=" + height +
'}';
}
}
Dog.java
package org.garen.strategy;
/**
* 狗
*/
public class Dog {
private int food; // 饭量
private int fur; // 毛
private int temper; // 脾气
public Dog(int food) {
this.food = food;
}
@Override
public String toString() {
return "Dog{" +
"food=" + food +
'}';
}
public int getFood() {
return food;
}
public void setFood(int food) {
this.food = food;
}
}
排序类Sorter.java
package org.garen.strategy;
/**
* 排序
*/
public class Sorter<T> {
/**
* 排序
* @param arr 数组
*/
public void sort(T[] arr, Comparator<T> comparator) {
for (int i = 0; i < arr.length; i++) {
int minPos = i;
for (int j = i+1; j < arr.length; j++) {
minPos = comparator.compareTo(arr[j], arr[minPos]) == -1 ? j : minPos;
}
swap(arr, i, minPos);
}
}
/**
* 交换位置
* @param arr T类型数组
* @param i 数组下标
* @param j 数组下标
*/
void swap(T[] arr, int i, int j) {
T temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
比较器
接口Comparator.java
package org.garen.strategy;
/**
* 比较器
*/
public interface Comparator<T> {
/**
* 比较
* @param t1 对象1
* @param t2 对象2
* @return 比较结果
*/
int compareTo(T t1, T t2);
}
Integer比较器
package org.garen.strategy;
/**
* 正序比较器
*/
public class IntegerAscComparator implements Comparator<Integer>{
@Override
public int compareTo(Integer t1, Integer t2) {
if(t1 < t2) return -1;
else if(t1 > t2) return 1;
else return 0;
}
}
package org.garen.strategy;
/**
* 倒序比较器
*/
public class IntegerDescComparator implements Comparator<Integer>{
@Override
public int compareTo(Integer t1, Integer t2) {
if(t1 > t2) return -1;
else if(t1 < t2) return 1;
else return 0;
}
}
Cat比较器
package org.garen.strategy;
/**
* 猫,重量比较器
*/
public class CatWeightComparator implements Comparator<Cat>{
@Override
public int compareTo(Cat t1, Cat t2) {
if(t1.weight < t2.weight) return -1;
else if(t1.weight > t2.weight) return 1;
else return 0;
}
}
package org.garen.strategy;
/**
* 猫,身高比较器
*/
public class CatHeightComparator implements Comparator<Cat> {
@Override
public int compareTo(Cat t1, Cat t2) {
if(t1.height < t2.height) return -1;
else if(t1.height > t2.height) return 1;
else return 0;
}
}
Dog比较器
package org.garen.strategy;
public class DogFoodComparator implements Comparator<Dog>{
@Override
public int compareTo(Dog t1, Dog t2) {
if(t1.getFood() < t2.getFood()) return -1;
else if(t1.getFood() > t2.getFood()) return 1;
else return 0;
}
}
测试类
package org.garen.strategy;
import java.util.Arrays;
/**
* 测试类
*/
public class Main {
public static void main(String[] args) {
// int数组排序
Integer[] a = {9, 2, 3, 5, 7, 1, 4};
// 策略:正序
new Sorter<Integer>().sort(a, new IntegerAscComparator());
System.out.println(Arrays.toString(a));
// 策略:倒序
new Sorter<Integer>().sort(a, new IntegerDescComparator());
System.out.println(Arrays.toString(a));
// Cat数组排序
Cat[] b = {new Cat(5, 5), new Cat(3, 3), new Cat(1, 1)};
// 策略:按照重量比较
new Sorter<Cat>().sort(b, new CatWeightComparator());
System.out.println(Arrays.toString(b));
// 策略:按照身高比较
new Sorter<Cat>().sort(b, new CatHeightComparator());
System.out.println(Arrays.toString(b));
// Dog数组排序
Dog[] c = {new Dog(3), new Dog(5), new Dog(2)};
// 策略:按照食量比较
new Sorter<Dog>().sort(c, new DogFoodComparator());
System.out.println(Arrays.toString(c));
// 如果以后需要按照毛多少、性格温顺程度等排序,增加相应的比较器即可,不用动现有代码
}
}
运行结果
[1, 2, 3, 4, 5, 7, 9]
[9, 7, 5, 4, 3, 2, 1]
[Cat{weight=1, height=1}, Cat{weight=3, height=3}, Cat{weight=5, height=5}]
[Cat{weight=1, height=1}, Cat{weight=3, height=3}, Cat{weight=5, height=5}]
[Dog{food=2}, Dog{food=3}, Dog{food=5}]
可见,代码复杂度提高了。那么为什么还要用策略模式呢?
设计模式中有一个原则,开闭原则。即:对修改关闭,对新增开放。也就是说,写好的代码,尽量不去修改它,有新功能就写新的代码实现。
这样代码是累加的过程,不会对之前的代码有影响,版本升级仍然可以兼容旧版本。
扩展性强,比如狗的排序,如果以后需要按照毛多少、性格温顺程度等排序,增加相应的比较器即可,不用动现有代码。