您的位置:首页 > 编程语言 > Java开发

Java设计模式之策略模式

2014-03-12 11:46 405 查看

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、给你一个狗的数组、如何调用别的类对其进行排序?

               是不是有一点点烦躁、感觉很啰嗦?在实际的需求中、我们所要面对的比这个恶心的比比皆是、我们常常说一个项目好、为什么好?标准是什么?三个词:灵活性强、可扩展性强、健壮!一个项目开发完成所需要我们coding的代码量、远远比不上我们后期维护他和扩展新功能的代码量。所以、需求不停的变动无处不在!借用一句话:A application must grow and change or it will die
!
               两只狗怎么比较?给你一个标准、根据狗的饭量来比较大小

               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的大小

                我想使用猫的身高来比较、我想使用猫的体重来比较、我想使用身高加体重综合值来比较、我想使用猫的胡子的长度来比较、我想想想想。。。。这样没完没了的客户如果提出这样的要求、你会选择一直添加新类、修改代码、重复重复在重复、还是说滚出、还是寻找一种很爽的方式来解决问题?我选第三....因为要靠客户吃饭。

                a) 站在高一点的角度去思考一下:是不是我可以定义一系列的策略、或者临时添加一系列的策略、而猫可以动态的调用我们指定的策略来实现比较呢?这样我们就可以完全不用管猫内部和排序内部是怎么实现、我们只需要定义我们自己的策略就ok。比如想根据猫的身高比较、那我就定义一种根据身高比较的策略——CatHeightCompareStrategy、然后将猫的比较策略设置成它。这样不就好了?那如何实现呢?

                b) 要达到这种目的、我们就要在猫的类中添加一个所有策略的引用、因为可以指定所有策略、所以定义一个接口是无比合适的、比较器——Comparator:

package com.chy.dp.strategy;

public interface Comparator {
//两个要比较的类
public int comparaTo(Object o1, Object o2);
}


                c) 自己定义个比较策略、需要实现ComparaTor接口、比如根据猫的身高来比较——CatHeightCompareStrategy:

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);
}
}

到此、策略模式也就告一段落了。

三:总结与补充

        1、总结:

                策略模式(StrArray Pattern)、就是动态的选择我们指定的策略来解决问题、在项目开发中、我们完全可以使用配置文件来动态的指定要使用的策略、这样灵活性、和可扩展性无疑得到了很大的提升、不必我们再痛苦的去重复的添加、修改实现方式。可以对比JDK中的实现

        2、补充:项目结构图:
                 


更多内容:Java设计模式之起始

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息