`
kang
  • 浏览: 474384 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

从诸葛亮的三个锦囊妙计谈策略模式

阅读更多

话说当年东吴孙权为刘备借走了荆州不还而耿耿于怀,却不料甘夫人去世,周郎顿时 计上心来,让孙权将其妹嫁与刘备,骗刘备来东吴完婚。刘备又不是傻子,当然知道其中的猫腻,当即表态:打死也不去。诸葛亮却说无妨,当下给了赵云三个锦囊 妙计,让他陪刘备去东吴完婚……最后的结果大家都知道,赵云在恰当的时候一一打开三个锦囊妙计,从而将危机一一化解。周瑜只落了个“周郎妙计安天下,赔了 夫人又折兵”的笑柄。
这个故事,我们感兴趣的是三个锦囊妙计。诸葛亮一定是运用策略模式的高手,我们 想啊:诸葛亮为什么要这么麻烦,做三个锦囊,他完全可以只做一个锦囊,将这三个妙计都写在它上面。可他没有这么做,而是正确的运用了策略模式做了三个锦 囊。这样做的好处十分明显:诸葛亮一个锦囊写一个妙计,他的思路十分清晰,不会三个计策相互混乱。而赵云看妙计的时候也十分方便,什么时候看哪个妙计,使 用十分方便,如果三个妙计混在一起,他就没这么方便了。
现在看来,这个故事正包含了策略模式的解决问题的思路:解决某一问题有多种方法或算法,如诸葛亮给了三个妙计,类的提供者要将这多种方法或算法独立开来,如诸葛亮将三个妙计分三个锦囊装,类的使用者,如赵云,在相应的条件,如故事中的恰当时间,使用相应的方法或算法。
前面我们说过命令模式,命令模式是对行为的封装;策略模式其实跟它的解决思路一样,是对算法的封装。当然,它们都一样的拥有同一个接口。
下面我们以一些例子来详细的说一说策略模式。
首先的一个例子是我们对数组的排序,对数组的排序有很多算法,我们想做一个由用户指定一个整形数组和对它排序的算法,我们给出结果这样一个方法,我们可以这样做:
public int[] sort(int[] inArray,String type)
{
       if(type.equals(“a”))
        {
               int k = 0;
               for(int i=0;i<inArray.length;i++)
               {
                      for(int j=i+1;j<inArray.length;j++)
                      {

                             if(inArray[i]> inArray[j])
                             {

                                    k = inArray[i];

                                    inArray[i] = inArray[j];

                                    inArray[j] = k;
                             }
                      }
               }
}
else if(type.equals(“b”))
{
       int k = 0;
       for(int i=0;i< inArray.length;i++)
       {

              for(int j=0;j< inArray.length-i-1;j++)
              {
                     if(inArray [j]> inArray [j+1])
                     {
                            k = inArray [j];
                            inArray [j] = inArray [j+1];
                            inArray [j+1] = k;
                     }
              }
       }
}
}
分析:上述代码中,if判断语句的写法不太好,当type为null时就会产生空指针异常。
解决方案:应该使用“字符串常量.equals(字符串变量)”的方法来处理。(20090414追加)


一看上面的代码,大家就觉得问题很多:第一,所有的算法都搅和在一起,不满足单一职责原则。第二,依赖细节,不满足依赖颠倒原则。第三,扩展性不好,如果要增加一个新的算法,需要对该方法进行改动。
下面我们来看看策略模式的解决思路。
首先是对所有的算法抽象一个接口,这是为了满足扩展性的基本条件,几乎所有的模式都要以接口为基础:
public interface SortAlgorithm
{

        public void sort(int[] inArr);
}
然后是各个算法的具体实现,它们实现了SortAlgorithm接口,完成了对关注点的分离,满足单一职责原则:
public class SortOne implements SortAlgorithm
{

        public void sort(int[] inArr)
        {
               int k = 0;
               for(int i=0;i<inArr.length;i++)
               {
                      for(int j=i+1;j<inArr.length;j++)
                      {

                             if(inArr[i]> inArr[j])
                             {

                                    k = inArr[i];

                                    inArr[i] = inArr[j];

                                    inArr[j] = k;
                             }
                      }
               }
}
}

public class SortTwo implements SortAlgorithm
{

        public void sort(int[] inArr)
        {
               int k = 0;
       for(int j=0;j< inArr.length-i-1;j++)
       {

              if(inArr[j]> inArr[j+1])
              {
                     k = inArr[j];
                     inArr[j] = inArr[j+1];
                     inArr[j+1] = k;
              }
               }
}
}
 
然后我们来看客户端的调用:

public int[] sort(int[] inArray,String type)
{
       SortAlgorithm sa;
       if(type.equals(“a”))
        {

               sa = new SortOne();
        }

        else if(type.equals(“b”))
        {

               sa = new SrotTwo();
}
else
{
       ……
}
sa.sort(inArray);
}
 

上面我们就完成了策略模式对该问题的解决,满足了单一职责原则;有了一定的扩展性,如果新增一个算法的话,去实现SortAlgorithm接口就可以了。
当然,我们在客户端代码可以看到,策略模式依然没有完全去掉客户端对具体实现类 的依赖,这使得我们增加一个新的算法以后,仍然需要对客户端进行修改。所以策略模式和命令模式一样,只是初步增加了一定的扩展性。如果要完全去掉客户端对 具体类的依赖,可以结合工厂模式来对该问题作进一步优化,具体做法大家可以自己做,这里不再讲述。
所谓策略模式,简单说来就是对算法的封装。在实际的编码过程中,我们会遇到各种各种的选择算法的问题,这时候就可以使用策略模式了 ,下面以一个例子来作为本文的结束。
假设我们有一个POJO类:Employee,里面存储了很多用户的信息,如下:

public class Employee
{

        private int id;

        private String name;

        private double servedYears;
        ……

        public void setId(int id)
        {
               this.id = id;
}
public int getId()
{
       return this.id;
}

public void setName(String name)
{
       this.name = name;
}
public String getName()
{
       return this.name;
}

public void setServedYears(double servedYears)
{
       this.servedYears = servedYears;
}

public double getServedYears()
{
       return this.servedYears;
}
……
}
 
现在我们有一个关于Employee的数组,需要对数组进行排序,我们知道该使用Arrays.sort()对该数组进行排序,但是在使用该方法的时候,我们首先要实现Comparator接口,如下:
Arrays.sort(emps,new Comparator(){

        Public int compare(Object o1,Object o2)
        {

               return ((Employee)o1).getServedYears()-((Employee)o2).getServedYears();
}
});
 
上面实现了一个对POJO对象的排序过程,现在的问题是我们分别需要对Employee类的id、name和servedYears为索引进行排序。我们可以看出,这明显是多个算法的问题,可以使用策略模式来解决问题:
以id为索引的比较器:

public class IdComparator implements Comparator
{

        Public int compare(Object o1,Object o2)
        {

               return ((Employee)o1).getId()-((Employee)o2).getId();
}
}
以name为索引的比较器:
public class NameComparator implements Comparator
{

        Public int compare(Object o1,Object o2)
        {

               return ((Employee)o1).getName()-((Employee)o2).getName();
}
}
 
以servedYears为索引的比较器:
public class ServedYearsComparator implements Comparator
{

        Public int compare(Object o1,Object o2)
        {

               return ((Employee)o1).getservedYears()-((Employee)o2).getServedYears();
}
}
 
然后,我们做一个工厂来获取具体的比较器:

public class Factory
{

        public static Comparator getInstance(String type)
        {
               if(type.equals(“id”))
               {
                      return new IdComparator();
}
else if(type.equals(“name”))
{
   return new NameComparator();
}
else
{
   return ServedYearsComparator();
}
}
}
 

那么我们就可以对客户端进行编码了:

public void sort(Employee[] emps,String type)
{
       Arrays.sort(emps,Factory.getInstance(type));
}
 
我们可以看到,结合了工厂模式的策略模式的确使多算法的问题得到了很好的解决:抽取了各个算法来单独关注,满足了单一职责原则;满足了依赖颠倒原则,有了很好的扩展性。 等等。
还等什么呢?赶快到实践中去灵活运用这些模式吧!


说明:本文摘自http://blog.csdn.net/hivon/archive/2006/01/23/586579.aspx




我的个人理解(20090408追加):结果集处理(将结果集映射成对象或者其他类型)方法,将其放在接口中声明。具体实现类实现这个接口,重写该方法:可以将结果集映射成对象(比如User对象),这就是一种策略;再写一个复写方法,将结果集映射成String类型(比如仅仅取得用户名),这又是一种策略。现在,就有两种策略了,可以根据实际要求,选择合适的映射方法(策略),得到合适的想定结果,这就是设计模式中的策略模式。


分享到:
评论

相关推荐

    详解Java设计模式编程中的策略模式

    Java设计模式中的策略模式是一种行为设计模式,它允许在运行时选择不同的算法或策略,以适应不同的业务需求。策略模式的核心思想是将算法封装到独立的类中,这些类遵循一个公共接口,使得它们可以相互替换。这样做的...

    策略模式和代理模式.docx

    以诸葛亮给赵云的三个锦囊妙计为例,每个锦囊代表一种策略,赵云根据战场情况选择使用不同的锦囊,即选择不同的策略来应对变化。 相对于策略模式,代理模式则更侧重于控制对某一对象的访问。在代理模式中,代理对象...

    高手谈设计模式高手谈设计模式

    策略模式:刘备要到江东娶老婆了,走之前诸葛亮给赵云(伴郎)三个锦囊妙计,说是按天机拆开 解决棘手问题,嘿,还别说,真是解决了大问题,搞到最后是周瑜陪了夫人又折兵呀,那咱 们先看看这个场景是什么样子的。 先...

    我们的设计模式(java)

    以诸葛亮给赵云三个锦囊妙计的故事情境为例,策略模式可以理解为诸葛亮就是环境(Context),锦囊妙计就是封装的策略(Strategy),而赵云则是使用这些策略的具体对象。 书中的每一个设计模式都附有UML类图和Java...

    java设计模式---诙谐易懂版

    3. 根据文件内容,诸葛亮给赵云的三个锦囊妙计可以用策略模式来实现。每个妙计对应一个实现了策略接口的具体策略类。例如,BackDoor类实现了IStrategy接口,它代表了“找乔国老帮忙,让吴国太给孙权施加压力”的策略...

    CBF4LIFE的《设计模式讲解JAVA》

    CBF4LIFE通过诸葛亮给赵云三个锦囊妙计的故事,形象地说明了策略模式的应用。在Java中,策略模式通常包括一个策略接口和多个实现该接口的具体策略类。客户端程序可以在运行时根据不同的条件选择不同的策略来实现不同...

    java 设计模式经典搞笑珍藏版

    在文档中,诸葛亮为赵云准备的三个锦囊妙计分别代表了不同的策略,赵云根据情况选择不同的策略来应对问题。 在面向对象编程中,策略模式涉及到以下几个关键概念: 1. 策略接口(Strategy Interface):定义了一个...

    24种设计模式介绍与6大设计原则.pdf

    故事中赵云执行诸葛亮给出的锦囊妙计就是策略模式的应用。 - **策略接口**:定义了算法的操作,如诸葛亮给出的锦囊妙计。 - **具体策略**:实现了策略接口的不同算法,如“找乔国老帮忙”等。 ### 编程实践 文档...

    设计模式_简单易懂的例子,且很有意思

    以上提到的三国故事中,诸葛亮为赵云准备了三个锦囊妙计,用于应对不同的情况。这里我们可以看到策略模式的应用。首先定义了一个`IStrategy`接口,表示一种策略或算法: ```java public interface IStrategy { ...

    24种设计模式

    在这个例子中,通过诸葛亮给赵云三个锦囊妙计的故事,生动地展示了策略模式的精髓。 策略模式包含以下几个要素: 1. 策略接口(Strategy):定义了算法家族,让算法的变化独立于使用算法的客户。 2. 具体策略...

    我们的设计模式(绝对通俗易懂)

    **示例**:如文中所举的例子,诸葛亮给赵云三个锦囊妙计,实际上就是三种不同的策略。每种策略对应一种处理紧急情况的方法。在 Java 中,可以通过定义一个策略接口(`IStrategy`)来表示这三种策略,然后分别实现该...

    设计模式与设计原则.pdf

    - 策略模式可以应用在有多个条件分支语句的场景中,通过将每个条件分支封装成一个策略类,使得系统更加灵活且易于扩展。 - 模式的设计通常需要引入一些新的角色和术语,如“锦囊妙计”代表策略,“赵云”代表使用...

    C++设计模式

    以《三国演义》中的典故为例,诸葛亮给赵云三个锦囊妙计,每个锦囊中都包含一种不同的策略来应对不同的情境。这可以类比为策略模式的应用场景,在实际编程中,策略模式允许我们在运行时选择不同的算法来解决问题。 ...

    24种设计模式介绍与6大设计原则

    例如,在上述例子中,诸葛亮为赵云提供了三个锦囊妙计,这实际上就是一个简单的策略模式的应用。其中,策略接口`IStrategy`定义了一个公共的操作方法`operate()`,而具体的策略如`BackDoor`实现了这一接口。 **2. ...

    java设计模式

    - **示例**:如文中所述的刘备过江东的例子中,诸葛亮给了赵云三个锦囊妙计,每一个锦囊中都包含了不同的策略来应对可能出现的情况。 - **实现**:通过定义一个接口`IStrategy`,然后为每种策略提供一个具体的实现...

    JAVA设计模式(经典)

    根据文档提供的示例,策略模式被比作三国时期刘备迎娶孙尚香时诸葛亮给予赵云的三个锦囊妙计。在这个例子中,“锦囊”代表策略的载体,“妙计”则代表具体的算法或行为。通过这种方式,策略模式能够帮助理解如何在...

Global site tag (gtag.js) - Google Analytics