Java设计模式之策略模式


转载自   http://blog.csdn.net/crave_shy/article/details/21075763#t8

 

        摘要:本篇笔记主要是对策略模式(StrategyPattern)学习过程、心得的记录。主要是通过模仿JDK中关于类的比较的方式来实现可以使用指定的方法、指定的策略来比较两个类的大小。

 

一:简介

 

        三十六计走为上策、这句话我们肯定不会陌生!策略、就是我们针对不同的时期、或者不同的情况、动态的选择合适的应对方式、这种应对方式可以称作是一种策略。

        Java的设计模式的原则中不会少得了flexible、extensible。下面通过模仿JDK的比较方式来展示策略模式的设计思想。当然一口吃不成胖子、还是老套路、围绕问题去一步一步深入探索。

 

二:问题的引出及解决

 

        1、给你一个int型数组、如何调用别的类对其进行排序?

 

                是不是觉得没什么难度?这里就暂时不要考虑JDK为我们提供的Arrays.sort(Object[] o)这种已经实现的工具类、假设没有、完全要我们自己去实现。你怎么实现?下面是一种实现:

                a)、 先写测试类、这样的一个好处就是你知道下一步要干嘛——Client代码:


[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. package com.chy.dp.strategy;  
  2.   
  3. public class Client {  
  4.     public static void main(String[] args) {  
  5.         int[] a = {3,4,2,5,1};  
  6.         DataSort.sort(a);  
  7.         DataSort.print(a);  
  8.     }  
  9. }  

                b)、 实现测试类中DataSort代码:

       

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. package com.chy.dp.strategy;  
  2.   
  3. public class DataSort {  
  4.   
  5.     /** 
  6.      * there many ways to sort an array,  
  7.      * but i just use the bubble sort to sort it. 
  8.      * i'll use other ways to sort it if i has more time. 
  9.      * @param a the array will be sorted. 
  10.      */  
  11.     public static void sort(int[] a) {  
  12.         for (int j = 0; j < a.length; j++) {  
  13.             for (int i = 0; i < a.length - j -1; i++) {  
  14.                 if(a[i] > a[i + 1]){  
  15.                     swap(a, i, i+1);  
  16.                 }  
  17.             }  
  18.         }  
  19.     }  
  20.   
  21.     /** 
  22.      * change the two elements of an array. 
  23.      * @param a an array. 
  24.      * @param i the first element index. 
  25.      * @param j the next element index. 
  26.      */  
  27.     private static void swap(int[] a, int i, int j) {  
  28.         int temp = a[i];  
  29.         a[i] = a[j];  
  30.         a[j] = temp;  
  31.     }  
  32.   
  33.     public static void print(int[] a) {  
  34.         for (int i = 0; i < a.length; i++) {  
  35.             System.out.print(a[i] + " ");  
  36.         }  
  37.     }  
  38. }  


        2、给你一个猫的数组、如何调用别的类对其进行排序?


               两只猫怎么比较?给你一个标准、猫有一个身高、一个体重、根据身高来比较猫的大小、这样一来是不是也觉得没什么难度?

               a) 要比较猫、当然要有一个Cat类:


[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. package com.chy.dp.strategy;  
  2.   
  3. public class Cat {  
  4.     private int height;  
  5.     private int weight;  
  6.   
  7.     public Cat(int height, int weight) {  
  8.         super();  
  9.         this.height = height;  
  10.         this.weight = weight;  
  11.     }  
  12.   
  13.     public int getHeight() {  
  14.         return height;  
  15.     }  
  16.   
  17.     public void setHeight(int height) {  
  18.         this.height = height;  
  19.     }  
  20.   
  21.     public int getWeight() {  
  22.         return weight;  
  23.     }  
  24.   
  25.     public void setWeight(int weight) {  
  26.         this.weight = weight;  
  27.     }  
  28.   
  29.     @Override  
  30.     public String toString() {  
  31.         return height + "|" + weight;  
  32.     }  
  33. }  

               b)那调用DataSort的Client代码:


[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. package com.chy.dp.strategy;  
  2.   
  3. public class Client {  
  4.     public static void main(String[] args) {  
  5.         // int[] a = {3,4,2,5,1};  
  6.         Cat[] a = {new Cat(1,1), new Cat(4,4), new Cat(2,2)};  
  7.         DataSort.sort(a);  
  8.         DataSort.print(a);  
  9.     }  
  10. }  

               c)同样DataSort也要变:


[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. package com.chy.dp.strategy;  
  2.   
  3. public class DataSort {  
  4.   
  5.     /** 
  6.      * there many ways to sort an array,  
  7.      * but i just use the bubble sort to sort it. 
  8.      * i'll use other ways to sort it if i has more time. 
  9.      * @param a the array will be sorted. 
  10.      */  
  11.     public static void sort(Cat[] a) {  
  12.         for (int j = 0; j < a.length; j++) {  
  13.             for (int i = 0; i < a.length - j -1; i++) {  
  14.                 if(a[i].getHeight() > a[i + 1].getHeight()){  
  15.                     swap(a, i, i+1);  
  16.                 }  
  17.             }  
  18.         }  
  19.     }  
  20.   
  21.     /** 
  22.      * change the two elements of an array. 
  23.      * @param a an array. 
  24.      * @param i the first element index. 
  25.      * @param j the next element index. 
  26.      */  
  27.     private static void swap(Cat[] a, int i, int j) {  
  28.         Cat temp = a[i];  
  29.         a[i] = a[j];  
  30.         a[j] = temp;  
  31.     }  
  32.   
  33.     public static void print(Cat[] a) {  
  34.         for (int i = 0; i < a.length; i++) {  
  35.             System.out.print(a[i] + " ");  
  36.         }  
  37.     }  
  38. }  


        3、给你一个狗的数组、如何调用别的类对其进行排序?


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

               两只狗怎么比较?给你一个标准、根据狗的饭量来比较大小

               a) 同样要比较狗、当然要有一个Dog类:


[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. package com.chy.dp.strategy;  
  2.   
  3. public class Dog {  
  4.     private int food;  
  5.   
  6.     public Dog(int food) {  
  7.         super();  
  8.         this.food = food;  
  9.     }  
  10.   
  11.     public int getFood() {  
  12.         return food;  
  13.     }  
  14.   
  15.     public void setFood(int food) {  
  16.         this.food = food;  
  17.     }  
  18.   
  19.     @Override  
  20.     public String toString(){  
  21.         return food + "";  
  22.     }  
  23. }  

               b)那调用DataSort的Client代码:


[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. package com.chy.dp.strategy;  
  2.   
  3. public class Client {  
  4.     public static void main(String[] args) {  
  5.         // int[] a = {3,4,2,5,1};  
  6.         //Cat[] a = {new Cat(1,1), new Cat(4,4), new Cat(2,2)};  
  7.         Dog[] a = {new Dog(1), new Dog(5), new Dog(3)};  
  8.         DataSort.sort(a);  
  9.         DataSort.print(a);  
  10.     }  
  11. }  

               c)同样DataSort也要变:


[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. package com.chy.dp.strategy;  
  2.   
  3. public class DataSort {  
  4.   
  5.     /** 
  6.      * there many ways to sort an array,  
  7.      * but i just use the bubble sort to sort it. 
  8.      * i'll use other ways to sort it if i has more time. 
  9.      * @param a the array will be sorted. 
  10.      */  
  11.     public static void sort(Dog[] a) {  
  12.         for (int j = 0; j < a.length; j++) {  
  13.             for (int i = 0; i < a.length - j -1; i++) {  
  14.                 if(a[i].getFood()> a[i + 1].getFood()){  
  15.                     swap(a, i, i+1);  
  16.                 }  
  17.             }  
  18.         }  
  19.     }  
  20.   
  21.     /** 
  22.      * change the two elements of an array. 
  23.      * @param a an array. 
  24.      * @param i the first element index. 
  25.      * @param j the next element index. 
  26.      */  
  27.     private static void swap(Dog[] a, int i, int j) {  
  28.         Dog temp = a[i];  
  29.         a[i] = a[j];  
  30.         a[j] = temp;  
  31.     }  
  32.   
  33.     public static void print(Dog[] a) {  
  34.         for (int i = 0; i < a.length; i++) {  
  35.             System.out.print(a[i] + " ");  
  36.         }  
  37.     }  
  38. }  

        4、给你一个牛类你如何进行上面说的操作?


                如果下面还是创建一个牛类、修改Client、修改DataSort、然后又是一个新的东西、你会不会觉得崩溃?如果不会、那么你试试比较一下十二生肖的大小、比较完了再比较一下所有动物的大小。。。

                所以这样下去、我们就会慢慢觉得这样不禁是很蛋疼的一件事、也是一个没有一点可取之处的东西、如何优化呢?如何才能更有扩展性、才能更灵活、在DataSort中不管你是什么类、我都可以用一个方法来比较传进来的大小?想到这里、首先进入脑海的我想应该是一个接口、定义一个比较方法的接口、让所有可以比较的类实现这个接口、并且提供自己的实现。不错、这是一种优化、如何实现?

                a) 创建一个包含一个比较方法的接口、所有想要实现比较大小功能的类都要实现这个接口、并且实现自己特有的方法——Comparable代码:


[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. package com.chy.dp.strategy;  
  2.   
  3. public interface Comparable {  
  4.     /** 
  5.      * @param the compared object. 
  6.      * @return  if this > o return  1;  
  7.      *          if this < o return -1; 
  8.      *          if this == o return 0;  
  9.      */  
  10.     public int compareTo(Object o);  
  11. }  

                b) 我们简单起见、这里只使用Cat作示例、Dog可以自己尝试。Cat实现Comparable接口(注意引入自己定义的、别与java.lang.util.Comparable弄混了)、并实现自己的compareTo方法。


[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. package com.chy.dp.strategy;  
  2.   
  3. public class Cat implements Comparable{  
  4.     private int height;  
  5.     private int weight;  
  6.   
  7.     public Cat(int height, int weight) {  
  8.         super();  
  9.         this.height = height;  
  10.         this.weight = weight;  
  11.     }  
  12.   
  13.     public int getHeight() {  
  14.         return height;  
  15.     }  
  16.   
  17.     public void setHeight(int height) {  
  18.         this.height = height;  
  19.     }  
  20.   
  21.     public int getWeight() {  
  22.         return weight;  
  23.     }  
  24.   
  25.     public void setWeight(int weight) {  
  26.         this.weight = weight;  
  27.     }  
  28.   
  29.     @Override  
  30.     public String toString() {  
  31.         return height + "|" + weight;  
  32.     }  
  33.   
  34.     @Override  
  35.     public int compareTo(Object o) {  
  36.         //如果参数都不是猫的实例、没有比较的意义、实际上这里是throw Exception、简单起见返回一个 -10  
  37.         if(!(o instanceof Cat)){  
  38.             return -10;  
  39.         }  
  40.         Cat cat = (Cat)o;  
  41.         if(this.getWeight() > cat.getWeight()){  
  42.             return 1;  
  43.         }else if ( this.getWeight() < cat.getWeight()){  
  44.             return -1;  
  45.         }else {  
  46.             return 0;  
  47.         }  
  48.     }  
  49. }  

                c) DataSort方法:


[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. package com.chy.dp.strategy;  
  2.   
  3. public class DataSort {  
  4.   
  5.     /** 
  6.      * there many ways to sort an array,  
  7.      * but i just use the bubble sort to sort it. 
  8.      * i'll use other ways to sort it if i has more time. 
  9.      * @param a the array will be sorted. 
  10.      */  
  11.     public static void sort(Comparable[] a) {  
  12.         for (int j = 0; j < a.length; j++) {  
  13.             for (int i = 0; i < a.length - j -1; i++) {  
  14.                 if(a[i].compareTo(a[i+1]) == 1){  
  15.                     swap(a, i, i+1);  
  16.                 }  
  17.             }  
  18.         }  
  19.     }  
  20.   
  21.     /** 
  22.      * change the two elements of an array. 
  23.      * @param a an array. 
  24.      * @param i the first element index. 
  25.      * @param j the next element index. 
  26.      */  
  27.     private static void swap(Comparable[] a, int i, int j) {  
  28.         Comparable temp = a[i];  
  29.         a[i] = a[j];  
  30.         a[j] = temp;  
  31.     }  
  32.   
  33.     public static void print(Comparable[] a) {  
  34.         for (int i = 0; i < a.length; i++) {  
  35.             System.out.print(a[i] + " ");  
  36.         }  
  37.     }  
  38. }  

                d) 这样是不是觉得爽多了、最起码我们的DataSort不再变化、不管你传进来的是什么、只要是实现Comparable接口、并且提供comparaTo方法的实现、我就可以为其进行排序!


        5、新问题:我想使用我指定的比较方式来比较Cat的大小


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

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

[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. package com.chy.dp.strategy;  
  2.   
  3. public interface Comparator {  
  4.     //两个要比较的类  
  5.     public int compare(Object o1, Object o2);  
  6. }  


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


[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. package com.chy.dp.strategy;  
  2.   
  3. public class CatHeightCompareStrategy implements Comparator {  
  4.       
  5.     @Override  
  6.     public int compare(Object o1, Object o2) {  
  7.         Cat c1 = (Cat) o1;  
  8.         Cat c2 = (Cat) o2;  
  9.         if(c1.getHeight() > c2.getHeight()){  
  10.             return 1;  
  11.         }else if(c1.getHeight() < c2.getHeight()){  
  12.             return -1;  
  13.         }else{  
  14.             return 0;  
  15.         }  
  16.     }  
  17. }  

                d) 让我们所想使用比较功能的类、聚合这个接口、即持有它的引用——Cat


[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. package com.chy.dp.strategy;  
  2.   
  3. public class Cat implements Comparable {  
  4.     private int height;  
  5.     private int weight;  
  6.   
  7.     // 持有Comparator的实例的一个引用并且给一个默认实现、我们可以通过set方法指定  
  8.     private Comparator comparator = new CatHeightCompareStrategy();  
  9.   
  10.     public Comparator getComparator() {  
  11.         return comparator;  
  12.     }  
  13.   
  14.     public void setComparator(Comparator comparator) {  
  15.         this.comparator = comparator;  
  16.     }  
  17.   
  18.     public Cat(int height, int weight) {  
  19.         super();  
  20.         this.height = height;  
  21.         this.weight = weight;  
  22.     }  
  23.   
  24.     public int getHeight() {  
  25.         return height;  
  26.     }  
  27.   
  28.     public void setHeight(int height) {  
  29.         this.height = height;  
  30.     }  
  31.   
  32.     public int getWeight() {  
  33.         return weight;  
  34.     }  
  35.   
  36.     public void setWeight(int weight) {  
  37.         this.weight = weight;  
  38.     }  
  39.   
  40.     @Override  
  41.     public String toString() {  
  42.         return height + "|" + weight;  
  43.     }  
  44.   
  45.     @Override  
  46.     public int compareTo(Object o) {  
  47.         // 如果参数都不是猫的实例、没有比较的意义、实际上这里是throw Exception、简单起见返回一个 -10  
  48.         return comparator.compare(this, (Cat)o);  
  49.     }  
  50. }  

                e) 测试我们的结果——Client:


[java]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. package com.chy.dp.strategy;  
  2.   
  3. public class Client {  
  4.     public static void main(String[] args) {  
  5.         // int[] a = {3,4,2,5,1};  
  6.         Comparable[] a = {new Cat(1,1), new Cat(4,4), new Cat(2,2)};  
  7.         DataSort.sort(a);  
  8.         DataSort.print(a);  
  9.     }  
  10. }  

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


三:总结与补充


        1、总结:

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

        2、补充:项目结构图:
                 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值