zoukankan      html  css  js  c++  java
  • 设计模式大类--行为模式(中)

    四、Chain of Responsibility(责任链)
    描述:一系列类(classes)试图处理一个请求request,这些类之间是一个松散的耦合,唯一共同点是在他们之间传递request. 也就是说,来了一个请求,A类先处理,如果没有处理,就传递到B类处理,如果没有处理,就传递到C类处理,就这样象一个链条(chain)一样传递下去
    好处:降低了类之间的耦合性

    例子:
    抽象处理者角色
    public abstract class Handler {

    /**
    * 持有后继的责任对象
    */
    protected Handler successor;
    /**
    * 示意处理请求的方法,虽然这个示意方法是没有传入参数的
    * 但实际是可以传入参数的,根据具体需要来选择是否传递参数
    */
    public abstract void handleRequest();
    /**
    * 取值方法
    */
    public Handler getSuccessor() {
    return successor;
    }
    /**
    * 赋值方法,设置后继的责任对象
    */
    public void setSuccessor(Handler successor) {
    this.successor = successor;
    }

    }

      具体处理者角色
    public class ConcreteHandler extends Handler {
    /**
    * 处理方法,调用此方法处理请求
    */
    @Override
    public void handleRequest() {
    /**
    * 判断是否有后继的责任对象
    * 如果有,就转发请求给后继的责任对象
    * 如果没有,则处理请求
    */
    if(getSuccessor() != null)
    {
    System.out.println("放过请求");
    getSuccessor().handleRequest();
    }else
    {
    System.out.println("处理请求");
    }
    }

    }

      客户端类
    public class Client {

    public static void main(String[] args) {
    //组装责任链
    Handler handler1 = new ConcreteHandler();
    Handler handler2 = new ConcreteHandler();
    handler1.setSuccessor(handler2);
    //提交请求
    handler1.handleRequest();
    }

    }
      可以看出,客户端创建了两个处理者对象,并指定第一个处理者对象的下家是第二个处理者对象,而第二个处理者对象没有下家。然后客户端将请求传递给第一个处理者对象。
      由于本示例的传递逻辑非常简单:只要有下家,就传给下家处理;如果没有下家,就自行处理。因此,第一个处理者对象接到请求后,会将请求传递给第二个处理者对象。由于第二个处理者对象没有下家,于是自行处理请求。

    五、Command(命令模式)
    描述:对命令进行封装,将发出命令的责任和执行命令的责任分割开
    好处:面向接口编程、能实现Undo功能。

    例子:
    典型的Command模式需要有一个接口.接口中有一个统一的方法,这就是"将命令/请求封装为对象":

    public interface Command {
      public abstract void execute ( );
    }


    具体不同命令/请求代码是实现接口Command,下面有三个具体命令

    public class Engineer implements Command {

      public void execute( ) {
        //do Engineer's command
      }
    }

    public class Programmer implements Command {

      public void execute( ) {
        //do programmer's command
      }
    }

    public class Politician implements Command {

      public void execute( ) {
        //do Politician's command
      }
    }

    按照通常做法,我们就可以直接调用这三个Command,但是使用Command模式,我们要将他们封装起来,扔到黑盒子List里去:

    public class producer{
      public static List produceRequests() {
        List queue = new ArrayList();
        queue.add( new DomesticEngineer() );
        queue.add( new Politician() );
        queue.add( new Programmer() );
        return queue;
      }

    }

    这三个命令进入List中后,已经失去了其外表特征,以后再取出,也可能无法分辨出谁是Engineer 谁是Programmer了,看下面如何调用Command模式:

    public class TestCommand {
      public static void main(String[] args) {
        
        List queue = Producer.produceRequests();
        for (Iterator it = queue.iterator(); it.hasNext(); )
            //取出List中东东,其他特征都不能确定,只能保证一个特征是100%正确,
            // 他们至少是接口Command的"儿子".所以强制转换类型为接口Command

            ((Command)it.next()).execute();
      

      }
    }

    由此可见,调用者基本只和接口打交道,不合具体实现交互,这也体现了一个原则,面向接口编程,这样,以后增加第四个具体命令时,就不必修改调用者TestCommand中的代码了.

    六、State(状态模式)
    描述:不同的状态,不同的行为;或者说,每个状态有着相应的行为
    优点:封装转换过程,也就是转换规则、枚举可能的状态,因此,需要事先确定状态种类。

    例子:
    请看下例:

    public class Context{

      private Color state=null;

      public void push(){

        //如果当前red状态 就切换到blue
        if (state==Color.red) state=Color.blue;

        //如果当前blue状态 就切换到green
        else if (state==Color.blue) state=Color.green;

        //如果当前black状态 就切换到red
        else if (state==Color.black) state=Color.red;

        //如果当前green状态 就切换到black
        else if (state==Color.green) state=Color.black;
        
        Sample sample=new Sample(state);
        sample.operate();
      }

      public void pull(){

        //与push状态切换正好相反

        if (state==Color.green) state=Color.blue;
        else if (state==Color.black) state=Color.green;
        else if (state==Color.blue) state=Color.red;
        else if (state==Color.red) state=Color.black;

        Sample2 sample2=new Sample2(state);
        sample2.operate();
      }

    }

    在上例中,我们有两个动作push推和pull拉,这两个开关动作,改变了Context颜色,至此,我们就需要使用State模式优化它.

    另外注意:但就上例,state的变化,只是简单的颜色赋值,这个具体行为是很简单的,State适合巨大的具体行为,因此在,就本例,实际使用中也不一定非要使用State模式,这会增加子类的数目,简单的变复杂.

    例如: 银行帐户, 经常会在Open 状态和Close状态间转换.

    例如: 经典的TcpConnection, Tcp的状态有创建 侦听 关闭三个,并且反复转换,其创建 侦听 关闭的具体行为不是简单一两句就能完成的,适合使用State

    例如:信箱POP帐号, 会有四种状态, start HaveUsername Authorized quit,每个状态对应的行为应该是比较大的.适合使用State

    例如:在工具箱挑选不同工具,可以看成在不同工具中切换,适合使用State.如 具体绘图程序,用户可以选择不同工具绘制方框 直线 曲线,这种状态切换可以使用State.

    如何使用
    State需要两种类型实体参与:

    1.state manager 状态管理器 ,就是开关 ,如上面例子的Context实际就是一个state manager, 在state manager中有对状态的切换动作.
    2.用抽象类或接口实现的父类,,不同状态就是继承这个父类的不同子类.

    以上面的Context为例.我们要修改它,建立两个类型的实体.
    第一步: 首先建立一个父类:

    public abstract class State{

      public abstract void handlepush(Context c);
      public abstract void handlepull(Context c);
      public abstract void getcolor();

    }

    父类中的方法要对应state manager中的开关行为,在state manager中 本例就是Context中,有两个开关动作push推和pull拉.那么在状态父类中就要有具体处理这两个动作:handlepush() handlepull(); 同时还需要一个获取push或pull结果的方法getcolor()

    下面是具体子类的实现:

    public class BlueState extends State{

      public void handlepush(Context c){
         //根据push方法"如果是blue状态的切换到green" ;
         c.setState(new GreenState());

      }
      public void handlepull(Context c){

         //根据pull方法"如果是blue状态的切换到red" ;
        c.setState(new RedState());

      }

      public abstract void getcolor(){ return (Color.blue)}

    }


    同样 其他状态的子类实现如blue一样.

    第二步: 要重新改写State manager 也就是本例的Context:

    public class Context{

      private Sate state=null; //我们将原来的 Color state 改成了新建的State state;

      //setState是用来改变state的状态 使用setState实现状态的切换
      pulic void setState(State state){

        this.state=state;

      }

      public void push(){

        //状态的切换的细节部分,在本例中是颜色的变化,已经封装在子类的handlepush中实现,这里无需关心
        state.handlepush(this);
        
        //因为sample要使用state中的一个切换结果,使用getColor()
        Sample sample=new Sample(state.getColor());
        sample.operate();

      }

      public void pull(){

        state.handlepull(this);
        
        Sample2 sample2=new Sample2(state.getColor());
        sample2.operate();

      }

    }


    至此,我们也就实现了State的refactorying过程

  • 相关阅读:
    Swift3 重写一个带占位符的textView
    Swift3 使用系统UIAlertView方法做吐司效果
    Swift3 页面顶部实现拉伸效果代码
    Swift3 倒计时按钮扩展
    iOS 获取当前对象所在的VC
    SpringBoot在IDEA下使用JPA
    hibernate 异常a different object with the same identifier value was already associated with the session
    SpringCloud IDEA 教学 番外篇 后台运行Eureka服务注册中心
    SpringCloud IDEA 教学 (五) 断路器控制台(HystrixDashboard)
    SpringCloud IDEA 教学 (四) 断路器(Hystrix)
  • 原文地址:https://www.cnblogs.com/aiguozhe/p/3763495.html
Copyright © 2011-2022 走看看