`

策略模式

阅读更多
1. 模式定义
   把会变的内容取出并封装起来,以便以后可以轻易地改动或扩充部分,而不影响不需要变化的其他部分!

2.设计原则
   把应用中变化的地方独立出来,不要和那些不需要变化的代码混在一起。这样代码变化引起的不经意后果变少,系统变得更有弹性。

3.本质
   少用继承,多用组合

1) 分开变化的内容和不变的内容

       Duck类中的行为 fly(), quack(), 每个子类型可能有自己特有的表现,这就是所谓的变化的内容。
           Duck类中的行为 swim() 每个子类型的表现均相同,这就是所谓不变的内容。

       我们将变化的内容从Duck()类中剥离出来单独定义形成接口以及一系列的实现类型。将变化的内容定义形成接口可实现变化内容和不变内容的剥离。其实现类型可实现变化内容的重用。这些实现类并非Duck.java的子类型,而是专门的一组实现类,称之为"行为类"。由行为类而不是Duck.java的子类型来实现接口。这样,才能保证变化的行为独立于不变的内容。于是我们有:

       变化的内容:
       //变化的 fly() 行为定义形成的接口
       public interface FlyBehavior {
        void fly();
       }
        
       //变化的 fly() 行为的实现类之一
       public class FlyWithWings implements FlyBehavior {
        public void fly() {
            System.out.println("I'm flying.");
        }
       }

       //变化的 fly() 行为的实现类之二
       public class FlyNoWay implements FlyBehavior {
        public void fly() {
            System.out.println("I can't fly.");
        }
       }

           -----------------------------------------------------------------
       //变化的 quack() 行为定义形成的接口
       public interface QuackBehavior {
        void quack();
       }

       //变化的 quack() 行为实现类之一
       public class Quack implements QuackBehavior {
        public void quack() {
            System.out.println("Quack");
        }
       }

       //变化的 quack() 行为实现类之二
       public class Squeak implements QuackBehavior {
        public void quack() {
            System.out.println("Squeak.");
        }
       }

       //变化的 quack() 行为实现类之三
       public class MuteQuack implements QuackBehavior {
        public void quack() {
            System.out.println("<< Slience >>");
        }
       }

       通过以上设计,fly()行为以及quack()行为已经和Duck.java没有什么关系,可以充分得到复用。而且我们很容易增加新的行为, 既不影响现有的行为,也不影响Duck.java。但是,大家可能有个疑问,就是在面向对象中行为不是体现为方法吗?为什么现在被定义形成类(例如 Squeak.java)?在OO中,类代表的"东西"一般是既有状态(实例变量)又有方法。只是在本例中碰巧"东西"是个行为。既使是行为,也有属性及方法,例如飞行行为,也需要一些属性记录飞行的状态,如飞行高度、速度等。

    2) 整合变化的内容和不变的内容

       Duck.java将 fly()以及quack()的行为委拖给行为类处理。

       不变的内容:
       public abstract class Duck {
            //将行为类声明为接口类型,降低对行为实现类型的依赖
        FlyBehavior flyBehavior;
        QuackBehavior quackBehavior;

        public void performFly() {
            //不自行处理fly()行为,而是委拖给引用flyBehavior所指向的行为对象
            flyBehavior.fly();
        }

        public void performQuack() {
            quackBehavior.quack();
        }

        public void swim() {
            System.out.println("All ducks float, even decoys.");       
        }
       
        public abstract void display();
       }

       Duck.java不关心如何进行 fly()以及quack(), 这些细节交由具体的行为类完成。
      
       public class MallardDuck extends Duck{
        public MallardDuck() {
            flyBehavior=new FlyWithWings();
            quackBehavior=new Quack();       
        }
       
        public void display() {
            System.out.println("Green head.");
        }
       }

           测试类:

       public class DuckTest {
        public static void main(String[] args) {
            Duck duck=new MallardDuck();
            duck.performFly();
            duck.performQuack();       
        }
       }

       在Duck.java子类型MallardDuck.java的构造方法中,直接实例化行为类型,在编译的时侯便指定具体行为类型。当然,我们可以:
     
       1) 我们可以通过工厂模式或其它模式进一步解藕(可参考后续模式讲解);
       2) 或做到在运行时动态地改变行为。

    3) 动态设定行为

       在父类Duck.java中增加设定行为类型的setter方法,接受行为类型对象的参数传入。为了降藕,行为参数被声明为接口类型。这样,既便在运行时,也可以通过调用这二个方法以改变行为。
       public abstract class Duck {
        //在刚才Duck.java中加入以下二个方法。
        public void setFlyBehavior(FlyBehavior flyBehavior) {
            this.flyBehavior=flyBehavior;
        }
       
        public void setQuackBehavior(QuackBehavior quackBehavior) {
            this.quackBehavior=quackBehavior;
        }

        //其它方法同,省略...
       }

           测试类:

       public class DuckTest {
        public static void main(String[] args) {
            Duck duck=new MallardDuck();
            duck.performFly();
            duck.performQuack();
            duck.setFlyBehavior(new FlyNoWay());
            duck.performFly();
        }
       }



上述代码是在别人博客中看到。为防忘记,我写在自己博客里。望原作者见谅!

原文http://www.iteye.com/topic/328262

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics