Java设计模式之策略模式
摘要:本篇笔记主要是对策略模式(StrategyPattern)学习过程、心得的记录。主要是通过模仿JDK中关于类的比较的方式来实现可以使用指定的方法、指定的策略来比较两个类的大小。
一:简介
三十六计走为上策、这句话我们肯定不会陌生!策略、就是我们针对不同的时期、或者不同的情况、动态的选择合适的应对方式、这种应对方式可以称作是一种策略。
Java的设计模式的原则中不会少得了flexible、extensible。下面通过模仿JDK的比较方式来展示策略模式的设计思想。当然一口吃不成胖子、还是老套路、围绕问题去一步一步深入探索。
二:问题的引出及解决
1、给你一个int型数组、如何调用别的类对其进行排序?
是不是觉得没什么难度?这里就暂时不要考虑JDK为我们提供的Arrays.sort(Object[] o)这种已经实现的工具类、假设没有、完全要我们自己去实现。你怎么实现?下面是一种实现:
a)、 先写测试类、这样的一个好处就是你知道下一步要干嘛——Client代码:
package com.chy.dp.strategy;
public class Client {
public static void main(String[] args) {
int[] a = {3,4,2,5,1};
DataSort.sort(a);
DataSort.print(a);
}
}
b)、 实现测试类中DataSort代码:
package com.chy.dp.strategy;
public class DataSort {
/**
* there many ways to sort an array,
* but i just use the bubble sort to sort it.
* i'll use other ways to sort it if i has more time.
* @param a the array will be sorted.
*/
public static void sort(int[] a) {
for (int j = 0; j < a.length; j++) {
for (int i = 0; i < a.length - j -1; i++) {
if(a[i] > a[i + 1]){
swap(a, i, i+1);
}
}
}
}
/**
* change the two elements of an array.
* @param a an array.
* @param i the first element index.
* @param j the next element index.
*/
private static void swap(int[] a, int i, int j) {
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
public static void print(int[] a) {
for (int i = 0; i < a.length; i++) {
System.out.print(a[i] + " ");
}
}
}
2、给你一个猫的数组、如何调用别的类对其进行排序?
两只猫怎么比较?给你一个标准、猫有一个身高、一个体重、根据身高来比较猫的大小、这样一来是不是也觉得没什么难度?
a) 要比较猫、当然要有一个Cat类:
package com.chy.dp.strategy;
public class Cat {
private int height;
private int weight;
public Cat(int height, int weight) {
super();
this.height = height;
this.weight = weight;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
@Override
public String toString() {
return height + "|" + weight;
}
}
b)那调用DataSort的Client代码:
package com.chy.dp.strategy;
public class Client {
public static void main(String[] args) {
// int[] a = {3,4,2,5,1};
Cat[] a = {new Cat(1,1), new Cat(4,4), new Cat(2,2)};
DataSort.sort(a);
DataSort.print(a);
}
}
c)同样DataSort也要变:
package com.chy.dp.strategy;
public class DataSort {
/**
* there many ways to sort an array,
* but i just use the bubble sort to sort it.
* i'll use other ways to sort it if i has more time.
* @param a the array will be sorted.
*/
public static void sort(Cat[] a) {
for (int j = 0; j < a.length; j++) {
for (int i = 0; i < a.length - j -1; i++) {
if(a[i].getHeight() > a[i + 1].getHeight()){
swap(a, i, i+1);
}
}
}
}
/**
* change the two elements of an array.
* @param a an array.
* @param i the first element index.
* @param j the next element index.
*/
private static void swap(Cat[] a, int i, int j) {
Cat temp = a[i];
a[i] = a[j];
a[j] = temp;
}
public static void print(Cat[] a) {
for (int i = 0; i < a.length; i++) {
System.out.print(a[i] + " ");
}
}
}
3、给你一个狗的数组、如何调用别的类对其进行排序?
两只狗怎么比较?给你一个标准、根据狗的饭量来比较大小
a) 同样要比较狗、当然要有一个Dog类:
package com.chy.dp.strategy;
public class Dog {
private int food;
public Dog(int food) {
super();
this.food = food;
}
public int getFood() {
return food;
}
public void setFood(int food) {
this.food = food;
}
@Override
public String toString(){
return food + "";
}
}
b)那调用DataSort的Client代码:
package com.chy.dp.strategy;
public class Client {
public static void main(String[] args) {
// int[] a = {3,4,2,5,1};
//Cat[] a = {new Cat(1,1), new Cat(4,4), new Cat(2,2)};
Dog[] a = {new Dog(1), new Dog(5), new Dog(3)};
DataSort.sort(a);
DataSort.print(a);
}
}
c)同样DataSort也要变:
package com.chy.dp.strategy;
public class DataSort {
/**
* there many ways to sort an array,
* but i just use the bubble sort to sort it.
* i'll use other ways to sort it if i has more time.
* @param a the array will be sorted.
*/
public static void sort(Dog[] a) {
for (int j = 0; j < a.length; j++) {
for (int i = 0; i < a.length - j -1; i++) {
if(a[i].getFood()> a[i + 1].getFood()){
swap(a, i, i+1);
}
}
}
}
/**
* change the two elements of an array.
* @param a an array.
* @param i the first element index.
* @param j the next element index.
*/
private static void swap(Dog[] a, int i, int j) {
Dog temp = a[i];
a[i] = a[j];
a[j] = temp;
}
public static void print(Dog[] a) {
for (int i = 0; i < a.length; i++) {
System.out.print(a[i] + " ");
}
}
}
4、给你一个牛类你如何进行上面说的操作?
如果下面还是创建一个牛类、修改Client、修改DataSort、然后又是一个新的东西、你会不会觉得崩溃?如果不会、那么你试试比较一下十二生肖的大小、比较完了再比较一下所有动物的大小。。。
所以这样下去、我们就会慢慢觉得这样不禁是很蛋疼的一件事、也是一个没有一点可取之处的东西、如何优化呢?如何才能更有扩展性、才能更灵活、在DataSort中不管你是什么类、我都可以用一个方法来比较传进来的大小?想到这里、首先进入脑海的我想应该是一个接口、定义一个比较方法的接口、让所有可以比较的类实现这个接口、并且提供自己的实现。不错、这是一种优化、如何实现?
a) 创建一个包含一个比较方法的接口、所有想要实现比较大小功能的类都要实现这个接口、并且实现自己特有的方法——Comparable代码:
package com.chy.dp.strategy;
public interface Comparable {
/**
* @param the compared object.
* @return if this > o return 1;
* if this < o return -1;
* if this == o return 0;
*/
public int compareTo(Object o);
}
b) 我们简单起见、这里只使用Cat作示例、Dog可以自己尝试。Cat实现Comparable接口(注意引入自己定义的、别与java.lang.util.Comparable弄混了)、并实现自己的compareTo方法。
package com.chy.dp.strategy;
public class Cat implements Comparable{
private int height;
private int weight;
public Cat(int height, int weight) {
super();
this.height = height;
this.weight = weight;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
@Override
public String toString() {
return height + "|" + weight;
}
@Override
public int compareTo(Object o) {
//如果参数都不是猫的实例、没有比较的意义、实际上这里是throw Exception、简单起见返回一个 -10
if(!(o instanceof Cat)){
return -10;
}
Cat cat = (Cat)o;
if(this.getWeight() > cat.getWeight()){
return 1;
}else if ( this.getWeight() < cat.getWeight()){
return -1;
}else {
return 0;
}
}
}
c) DataSort方法:
package com.chy.dp.strategy;
public class DataSort {
/**
* there many ways to sort an array,
* but i just use the bubble sort to sort it.
* i'll use other ways to sort it if i has more time.
* @param a the array will be sorted.
*/
public static void sort(Comparable[] a) {
for (int j = 0; j < a.length; j++) {
for (int i = 0; i < a.length - j -1; i++) {
if(a[i].compareTo(a[i+1]) == 1){
swap(a, i, i+1);
}
}
}
}
/**
* change the two elements of an array.
* @param a an array.
* @param i the first element index.
* @param j the next element index.
*/
private static void swap(Comparable[] a, int i, int j) {
Comparable temp = a[i];
a[i] = a[j];
a[j] = temp;
}
public static void print(Comparable[] a) {
for (int i = 0; i < a.length; i++) {
System.out.print(a[i] + " ");
}
}
}
d) 这样是不是觉得爽多了、最起码我们的DataSort不再变化、不管你传进来的是什么、只要是实现Comparable接口、并且提供comparaTo方法的实现、我就可以为其进行排序!
5、新问题:我想使用我指定的比较方式来比较Cat的大小
package com.chy.dp.strategy;
public interface Comparator {
//两个要比较的类
public int comparaTo(Object o1, Object o2);
}
package com.chy.dp.strategy;
public class CatHeightCompareStrategy implements Comparator {
@Override
public int comparaTo(Object o1, Object o2) {
Cat c1 = (Cat) o1;
Cat c2 = (Cat) o2;
if(c1.getHeight() > c2.getHeight()){
return 1;
}else if(c1.getHeight() < c2.getHeight()){
return -1;
}else{
return 0;
}
}
}
d) 让我们所想使用比较功能的类、聚合这个接口、即持有它的引用——Cat
package com.chy.dp.strategy;
public class Cat implements Comparable {
private int height;
private int weight;
// 持有Comparator的实例的一个引用并且给一个默认实现、我们可以通过set方法指定
private Comparator comparator = new CatHeightCompareStrategy();
public Comparator getComparator() {
return comparator;
}
public void setComparator(Comparator comparator) {
this.comparator = comparator;
}
public Cat(int height, int weight) {
super();
this.height = height;
this.weight = weight;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
@Override
public String toString() {
return height + "|" + weight;
}
@Override
public int compareTo(Object o) {
// 如果参数都不是猫的实例、没有比较的意义、实际上这里是throw Exception、简单起见返回一个 -10
return comparator.comparaTo(this, (Cat)o);
}
}
e) 测试我们的结果——Client:
package com.chy.dp.strategy;
public class Client {
public static void main(String[] args) {
// int[] a = {3,4,2,5,1};
Comparable[] a = {new Cat(1,1), new Cat(4,4), new Cat(2,2)};
DataSort.sort(a);
DataSort.print(a);
}
}
到此、策略模式也就告一段落了。