锐单电子商城 , 一站式电子元器件采购平台!
  • 电话:400-990-0325

软件设计模式学习笔记(九)

时间:2022-10-07 08:00:00 a1型变送器

行为型模式

1. 状态模式

1.1 概述

例通过按钮控制电梯的状态。电梯具有开门、关门、停止和运行状态。每种状态变化都可以根据其他状态进行更新。例如,如果电梯门处于运行状态,则无法开门,如果电梯门处于停止状态,则可以开门。

类图如下:

在这里插入图片描述

代码如下:

public interface ILift { 
             //电梯4个状态     ///开门状态     public final static int OPENING_STATE = 1;     ///关门状态     public final static int CLOSING_STATE = 2;     //运行状态     public final static int RUNNING_STATE = 3;     //停止状态     public final static int STOPPING_STATE = 4;      //设置电梯状态     public void setState(int state);      ///电梯动作     public void open();     public void close();     public void run();     public void stop(); }  public class Lift implements ILift { 
             private int state;      @Override     public void setState(int state) { 
                 this.state = state;     }      //执行关门动作     @Override     public void 
       
        close
        (
        ) 
        { 
          
        switch 
        (
        this
        .state
        ) 
        { 
          
        case OPENING_STATE
        : 
        System
        .out
        .
        println
        (
        "电梯关门了。。。"
        )
        ;
        //只有开门状态可以关闭电梯门,可以对应电梯状态表来看 
        this
        .
        setState
        (CLOSING_STATE
        )
        ;
        //关门之后电梯就是关闭状态了 
        break
        ; 
        case CLOSING_STATE
        : 
        //do nothing //已经是关门状态,不能关门 
        break
        ; 
        case RUNNING_STATE
        : 
        //do nothing //运行时电梯门是关着的,不能关门 
        break
        ; 
        case STOPPING_STATE
        : 
        //do nothing //停止时电梯也是关着的,不能关门 
        break
        ; 
        } 
        } 
        //执行开门动作 
        @Override 
        public 
        void 
        open
        (
        ) 
        { 
          
        switch 
        (
        this
        .state
        ) 
        { 
          
        case OPENING_STATE
        :
        /
        /门已经开了,不能再开门了 
        //do nothing 
        break
        ; 
        case CLOSING_STATE
        :
        /
        /关门状态,门打开
        : 
        System
        .out
        .
        println
        (
        "电梯门打开了。。。"
        )
        ; 
        this
        .
        setState
        (OPENING_STATE
        )
        ; 
        break
        ; 
        case RUNNING_STATE
        : 
        //do nothing 运行时电梯不能开门 
        break
        ; 
        case STOPPING_STATE
        : 
        System
        .out
        .
        println
        (
        "电梯门开了。。。"
        )
        ;
        //电梯停了,可以开门了 
        this
        .
        setState
        (OPENING_STATE
        )
        ; 
        break
        ; 
        } 
        } 
        //执行运行动作 
        @Override 
        public 
        void 
        run
        (
        ) 
        { 
          
        switch 
        (
        this
        .state
        ) 
        { 
          
        case OPENING_STATE
        :
        /
        /电梯不能开着门就走 
        //do nothing 
        break
        ; 
        case CLOSING_STATE
        :
        /
        /门关了,可以运行了 
        System
        .out
        .
        println
        (
        "电梯开始运行了。。。"
        )
        ; 
        this
        .
        setState
        (RUNNING_STATE
        )
        ;
        //现在是运行状态 
        break
        ; 
        case RUNNING_STATE
        : 
        //do nothing 已经是运行状态了 
        break
        ; 
        case STOPPING_STATE
        : 
        System
        .out
        .
        println
        (
        "电梯开始运行了。。。"
        )
        ; 
        this
        .
        setState
        (RUNNING_STATE
        )
        ; 
        break
        ; 
        } 
        } 
        //执行停止动作 
        @Override 
        public 
        void 
        stop
        (
        ) 
        { 
          
        switch 
        (
        this
        .state
        ) 
        { 
          
        case OPENING_STATE
        : 
        //开门的电梯已经是是停止的了(正常情况下) 
        //do nothing 
        break
        ; 
        case CLOSING_STATE
        :
        /
        /关门时才可以停止 
        System
        .out
        .
        println
        (
        "电梯停止了。。。"
        )
        ; 
        this
        .
        setState
        (STOPPING_STATE
        )
        ; 
        break
        ; 
        case RUNNING_STATE
        :
        /
        /运行时当然可以停止了 
        System
        .out
        .
        println
        (
        "电梯停止了。。。"
        )
        ; 
        this
        .
        setState
        (STOPPING_STATE
        )
        ; 
        break
        ; 
        case STOPPING_STATE
        : 
        //do nothing 
        break
        ; 
        } 
        } 
        } 
        public 
        class 
        Client 
        { 
          
        public 
        static 
        void 
        main
        (
        String
        [
        ] args
        ) 
        { 
          
        Lift lift 
        = 
        new 
        Lift
        (
        )
        ; lift
        .
        setState
        (
        ILift
        .STOPPING_STATE
        )
        ;
        //电梯是停止的 lift
        .
        open
        (
        )
        ;
        //开门 lift
        .
        close
        (
        )
        ;
        //关门 lift
        .
        run
        (
        )
        ;
        //运行 lift
        .
        stop
        (
        )
        ;
        //停止 
        } 
        } 
       

问题分析:

  • 使用了大量的switch…case这样的判断(if…else也是一样),使程序的可阅读性变差
  • 扩展性很差。如果新加了断电的状态,我们需要修改上面判断逻辑

定义:

对有状态的对象,把复杂的“判断逻辑”提取到不同的状态对象中,允许状态对象在其内部状态发生改变时改变其行为

1.2 结构

状态模式包含以下主要角色。

  • 环境(Context)角色:也称为上下文,它定义了客户程序需要的接口,维护一个当前状态,并将与状态相关的操作委托给当前状态对象来处理
  • 抽象状态(State)角色:定义一个接口,用以封装环境对象中的特定状态所对应的行为
  • 具体状态(Concrete State)角色:实现抽象状态所对应的行为

1.3 案例实现

对上述电梯的案例使用状态模式进行改进。类图如下:

代码如下:

//抽象状态类
public abstract class LiftState { 
        
    //定义一个环境角色,也就是封装状态的变化引起的功能变化
    protected Context context;

    public void setContext(Context context) { 
        
        this.context = context;
    }

    //电梯开门动作
    public abstract void open();

    //电梯关门动作
    public abstract void close();

    //电梯运行动作
    public abstract void run();

    //电梯停止动作
    public abstract void stop();
}

//开启状态
public class OpenningState extends LiftState { 
        

    //开启当然可以关闭了,我就想测试一下电梯门开关功能
    @Override
    public void open() { 
        
        System.out.println("电梯门开启...");
    }

    @Override
    public void close() { 
        
        //状态修改
        super.context.setLiftState(Context.closeingState);
        //动作委托为CloseState来执行,也就是委托给了ClosingState子类执行这个动作
        super.context.getLiftState().close();
    }

    //电梯门不能开着就跑,这里什么也不做
    @Override
    public void run() { 
        
        //do nothing
    }

    //开门状态已经是停止的了
    @Override
    public void stop() { 
        
        //do nothing
    }
}

//运行状态
public class RunningState extends LiftState { 
        

    //运行的时候开电梯门?你疯了!电梯不会给你开的
    @Override
    public void open() { 
        
        //do nothing
    }

    //电梯门关闭?这是肯定了
    @Override
    public void close() { 
        //虽然可以关门,但这个动作不归我执行
        //do nothing
    }

    //这是在运行状态下要实现的方法
    @Override
    public void run() { 
        
        System.out.println("电梯正在运行...");
    }

    //这个事绝对是合理的,光运行不停止还有谁敢做这个电梯?!估计只有上帝了
    @Override
    public void stop() { 
        
        super.context.setLiftState(Context.stoppingState);
        super.context.stop();
    }
}

//停止状态
public class StoppingState extends LiftState { 
        

    //停止状态,开门,那是要的!
    @Override
    public void open() { 
        
        //状态修改
        super.context.setLiftState(Context.openningState);
        //动作委托为CloseState来执行,也就是委托给了ClosingState子类执行这个动作
        super.context.getLiftState().open();
    }

    @Override
    public void close() { 
        //虽然可以关门,但这个动作不归我执行
        //状态修改
        super.context.setLiftState(Context.closeingState);
        //动作委托为CloseState来执行,也就是委托给了ClosingState子类执行这个动作
        super.context.getLiftState().close();
    }

    //停止状态再跑起来,正常的很
    @Override
    public void run() { 
        
        //状态修改
        super.context.setLiftState(Context.runningState);
        //动作委托为CloseState来执行,也就是委托给了ClosingState子类执行这个动作
        super.context.getLiftState().run();
    }

    //停止状态是怎么发生的呢?当然是停止方法执行了
    @Override
    public void stop() { 
        
        System.out.println("电梯停止了...");
    }
}

//关闭状态
public class ClosingState extends LiftState { 
        

    @Override
    //电梯门关闭,这是关闭状态要实现的动作
    public void close() { 
        
        System.out.println("电梯门关闭...");
    }

    //电梯门关了再打开,逗你玩呢,那这个允许呀
    @Override
    public void open() { 
        
        super.context.setLiftState(Context.openningState);
        super.context.open();
    }


    //电梯门关了就跑,这是再正常不过了
    @Override
    public void run() { 
        
        super.context.setLiftState(Context.runningState);
        super.context.run();
    }

    //电梯门关着,我就不按楼层
    @Override
    public void stop() { 
        
        super.context.setLiftState(Context.stoppingState);
        super.context.stop();
    }
}

//环境角色
public class Context { 
        
    //定义出所有的电梯状态
    public final static OpenningState openningState = new OpenningState();//开门状态,这时候电梯只能关闭
    public final static ClosingState closeingState = new ClosingState();//关闭状态,这时候电梯可以运行、停止和开门
    public final static RunningState runningState = new RunningState();//运行状态,这时候电梯只能停止
    public final static StoppingState stoppingState = new StoppingState();//停止状态,这时候电梯可以开门、运行


    //定义一个当前电梯状态
    private LiftState liftState;

    public LiftState getLiftState() { 
        
        return this.liftState;
    }

    public void setLiftState(LiftState liftState) { 
        
        //当前环境改变
        this.liftState = liftState;
        //把当前的环境通知到各个实现类中
        this.liftState.setContext(this);
    }

    public void open() { 
        
        this.liftState.open();
    }

    public void close() { 
        
        this.liftState.close();
    }

    public void run() { 
        
        this.liftState.run();
    }

    public void stop() { 
        
        this.liftState.stop();
    }
}

//测试类
public class Client { 
        
    public static void main(String[] args) { 
        
        Context context = new Context();
        context.setLiftState(new ClosingState());

        context.open();
        context.close();
        context.run();
        context.stop();
    }
}

1.4 优缺点

1,优点:

  • 将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为。
  • 允许状态转换逻辑与状态对象合成一体,而不是某一个巨大的条件语句块

2,缺点:

  • 状态模式的使用必然会增加系统类和对象的个数
  • 状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱
  • 状态模式对"开闭原则"的支持并不太好

1.5 使用场景

  • 当一个对象的行为取决于它的状态,并且它必须在运行时根据状态改变它的行为时,就可以考虑使用状态模式
  • 一个操作中含有庞大的分支结构,并且这些分支决定于对象的状态时

2. 观察者模式

2.1 概述

定义:

又被称为发布-订阅(Publish/Subscribe)模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化时,会通知所有的观察者对象,使他们能够自动更新自己。

2.2 结构

在观察者模式中有如下角色:

  • Subject:抽象主题(抽象被观察者),抽象主题角色把所有观察者对象保存在一个集合里,每个主题都可以有任意数量的观察者,抽象主题提供一个接口,可以增加和删除观察者对象
  • ConcreteSubject:具体主题(具体被观察者),该角色将有关状态存入具体观察者对象,在具体主题的内部状态发生改变时,给所有注册过的观察者发送通知
  • Observer:抽象观察者,是观察者的抽象类,它定义了一个更新接口,使得在得到主题更改通知时更新自己
  • ConcrereObserver:具体观察者,实现抽象观察者定义的更新接口,以便在得到主题更改通知时更新自身的状态

2.3 案例实现

【例】微信公众号

在使用微信公众号时,大家都会有这样的体验,当你关注的公众号中有新内容更新的话,它就会推送给关注公众号的微信用户端。我们使用观察者模式来模拟这样的场景,微信用户就是观察者,微信公众号是被观察者,有多个的微信用户关注了程序猿这个公众号。

类图如下:

代码如下:

定义抽象观察者类,里面定义一个更新的方法

public interface Observer { 
        
    void update(String message);
}

定义具体观察者类,微信用户是观察者,里面实现了更新的方法

public class WeixinUser implements Observer { 
        
    // 微信用户名
    private String name;

    public WeixinUser(String name) { 
        
        this.name = name;
    }
    @Override
    public void update(String message) { 
        
        System.out.println(name + "-" + message);
    }
}

定义抽象主题类,提供了attach、detach、notify三个方法

public interface Subject { 
        
    //增加订阅者
    public void attach(Observer observer);

    //删除订阅者
    public void detach(Observer observer);
    
    //通知订阅者更新消息
    public void notify(String message);
}

微信公众号是具体主题(具体被观察者),里面存储了订阅该公众号的微信用户,并实现了抽象主题中的方法

public class SubscriptionSubject implements Subject { 
        
    //储存订阅公众号的微信用户
    private List<Observer> weixinUserlist = new ArrayList<Observer>();

    @Override
    public void attach(Observer observer) { 
        
        weixinUserlist.add(observer);
    }

    @Override
    public void detach(Observer observer) { 
        
        weixinUserlist.remove(observer);
    }

    @Override
    public void notify(String message) { 
        
        for (Observer observer : weixinUserlist) { 
        
            observer.update(message);
        }
    }
}

客户端程序

public class Client { 
        
    public static void main(String[] args) { 
        
        SubscriptionSubject mSubscriptionSubject=new SubscriptionSubject();
        //创建微信用户
        WeixinUser user1=new WeixinUser("孙悟空");
        WeixinUser user2=new WeixinUser(

相关文章