• 设计模式第一集——策略模式


      《Head First——设计模式》真是一本太太太好的书了!!!之前一看设计模式就头疼,这本书浅显易懂越看越想看。

      首先,设计模式第一集——策略模式:定义算法族,分别封装起来,让他们之间可以相互替换,此模式让算法的变化独立于使用算法的客户。

      定义不好理解,举一个例子。

      假如现在要做一个模拟鸭子游戏,里面有各类鸭子。游戏中有各类鸭子,一边游泳(swim)一边嘎嘎叫(quack)。现在需要对原有的游戏代码进行改进,要求:

      1.在新增的游戏中,有些鸭子会飞;

      2.鸭子嘎嘎叫的方式有很多不同,比如有的吱吱叫;

      3.有一种模型鸭,可以动态的改变自己飞行行为(比如具备火箭动力飞行能力)

      针对上面的需求,很容易想到的是设计一个抽象的Duck类,该类里有swim、quack、fly等方法,其它类型的鸭子继承Duck类。这就是我完全不知道设计模式的时候想到的方法,这样设计有很多问题!比如:把fly的方法写到基类中,所有的类型鸭子继承之后都有了fly的能力,但是有些鸭子是不能飞的,就需要把这些鸭子的fly方法覆盖掉,n多个不能飞的鸭子就要覆盖n此,重复代码太多。同理,要求鸭子的嘎嘎叫法也不同,像之前的设计对于很多种鸭子都要重写它们的quack方法。

      那要怎么做?

      原则一:封装变化

      quack和fly的特性是不同鸭子有不同的方式,把他们从Duck的基类中拿出来,单独封装起来,建立一个新类来代表每一行为。这样对quack和fly方法的改变不会影响到其它部分。

      那怎么实现多种fly方式和quack方式呢?

      原则二:针对接口编程,而不针对实现编程

      这个很容易,分别写一个FlyBehavior和QuackBehavior的接口。具体想怎么飞怎么叫,在具体实现中去编吧。在Duck的基类中把之前写死的fly()和quack()方法去掉,改变成委托给FlyBehavior的引用

      public class FlyWithWings implments FlyBehavior{

            public void fly(){

                 System.out.println("用翅膀飞!");

             }

        }

        public abstract class Duck{

           FlyBehavior flyBehavior;

       QuackBehavior quackBehavior;

           public void swim(){……}

           public void performFly(){ flyBehavior.fly();}//委托给飞的行为类实现飞的动作

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

       }

        最后一个需求很简单,我们要动态的改变鸭子的行为,那在Duck中对鸭子的个个行为设立set()方法,当想让这个鸭子有哪种行为时,set一下就可以了。

      在最后还要提到一个原则三:多用组合,少用继承.FlyBehavior和QuackBehavior从之前的超类中拿出来,以组合的方式完成动作。

      鸭子游戏UML图:

      抽象的Duck类:

     1 package com.duck;
     2 
     3 public abstract class Duck {
     4     FlyBehavior flyBehavior;
     5     QuackBehavior quackBehavior;
     6     
     7     public abstract void display();
     8     
     9     //将飞、呱呱叫的行为委托给行为类
    10     public void performfly(){
    11         flyBehavior.fly();
    12     }
    13     public void performQuack(){
    14         quackBehavior.quack();
    15     }
    16     public void quackBehavior(){
    17         quackBehavior.quack();
    18     }
    19     
    20     public void swim(){
    21         System.out.println("I am swimming");
    22     }
    23     //动态设定行为
    24     public void setFlyBehavior(FlyBehavior fb){
    25         flyBehavior=fb;
    26     }
    27     public void setQuackBehavior(QuackBehavior qb){
    28         quackBehavior=qb;
    29     }
    30 }

      FlyBehavior接口:

     1 package com.duck;
     2 
     3 public interface FlyBehavior {
     4     public void fly();
     5 }
     6 
     7 package com.duck;
     8 
     9 public class FlyNoWay implements FlyBehavior{
    10     public void fly() {
    11     }
    12 
    13 }
    14 
    15 package com.duck;
    16 
    17 public class FlyWithWings implements FlyBehavior{
    18 
    19     @Override
    20     public void fly() {
    21         System.out.println("I am flying");
    22     }
    23 }

    QuackBehavior:

     1 package com.duck;
     2 
     3 public interface QuackBehavior {
     4     public void quack();
     5 }
     6 
     7 package com.duck;
     8 
     9 public class Quack implements QuackBehavior{
    10 
    11     public void quack() {
    12         System.out.println("Quack");
    13     }
    14 
    15 }
    16 
    17 package com.duck;
    18 
    19 public class Squeak implements QuackBehavior{
    20 
    21     public void quack() {
    22         System.out.println("Squeak");
    23         
    24     }
    25 
    26 }

     要实现一个具体的绿头鸭:

    现在嘎嘎叫的行为和飞的行为都是单独的类,这样对以后新增的鸭子可以直接组合想要的行为。将需要新的嘎嘎叫和飞行为的时候,写新的类实现实现。若有其他新的行为产生是,再写新的接口用和新的类具体实现。这样在代码维护的时候不用反复修改代码。

     1 package com.duck;
     2 
     3 public class MallardDuck extends Duck{
     4     
     5     public MallardDuck() {
     6         //绿头鸭的特点是可以呱呱叫和飞行
     7         //因为MallardDuck 继承自 Duck所以它具有quackBehavior和flybehavior实例变量
     8         quackBehavior=new Quack();//呱呱叫
     9         flyBehavior=new FlyWithWings();//
    10     }
    11 
    12     @Override
    13     public void display() {
    14         System.out.println("I am a real Mallard duck");
    15     }
    16 }
  • 相关阅读:
    基于springboot1.5.9整合shiro时出现静态文件找不到的问题
    基于springboot多模块项目使用maven命令打成war包放到服务器上运行的问题
    关于使用map存放数据乱序”问题“
    springboot1.5.9整合websocket实现实时显示的小demo
    SpringBoot1.5.10.RELEASE配置mybatis的逆向工程
    SpringBoot1.5.10.RELEASE整合druid时,在druid monitor界面出现(*) property for user to setup
    SpringBoot1.5.10.RELEASE整合druid
    SpringBoot1.5.10.RELEASE项目如何在tomcat容器中运行
    JS学习-01
    List,Set,Map在java.util包下都是接口 List有两个实现类:ArrayList和LinkedList Set有两个实现类:HashSet和LinkedHashSet AbstractSet实现了Set
  • 原文地址:https://www.cnblogs.com/doublesong/p/2613608.html
Copyright © 2020-2023  润新知