设计模式JAVA——1 策略与观察者模式

本博客内容大部分采集于《head first 设计模式》一书

策略模式

策略模式定义了算法族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。

对于多态,最常见的就是几个子类继承抽象类后覆盖父类方法,以达到自己的行为。但是造成的问题可能是:

  1. 代码在多个子类中重复。
  2. 运行时行为不能够改变。
  3. 假设同样的行为发生改变,将会修改所有拥有此行为的子类代码。

可能有人想到将这些行为抽出来作为接口,但是依然改变不了代码不可复用的问题,最好的解决办法就是这些行为委托给别人处理,当然,一个行为肯定由接口和若干实现类所组成。超类负责把行为委托,子类只需指定具体的实现类。

书中以鸭子为例,先看一下非策略模式的类图

再看看采用了策略模式下的类图

使用策略模式后,Duck类将行为接口作为引用变量,在perFormXXX()方法中将具体的行为委托给行为类;同时,还增加了setXXXBehavior()方法,这样子类在实例化后还可以动态的更改自己的行为。

public abstract class Duck{
    FlyBehavior flyBehavior;
    QuackBehavior quackBehavior;
    public Duck(){}
    public abstract void display();
    public void performFly(){
        flyBehavior.fly();
    }
    public void performQuack(){
        quackBehavior.quack();
    }
    public void setFlyBehavior(FlyBehavior fb){
        flyBehavior = fb;
    }
    public void setQuackBehavior(QuackBehavior qb){
        quackBehavior= qb;
    }
}

观察者模式

在对象之间定义了一对多的以来,这样一来,当一个对象改变状态,依赖它的对象都会收到通知并自动更新。

书中的例子是气象站与布告板

大致的功能就是:每当气象站所监测的数据发生更改,那么就通知布告板要变化显示的数据。

那么气象站将作为被观察者,或者叫做主题,它应该有一个变量保存所有的观察者,那么相应的就要有注册观察者的方法,和移除观察者的方法,同时还要有数据变化通知观察者的方法,以及自己获取数据的方法等等。

作为观察者,最主要的就是更新方法。而这个更新的方法可能是在主题类中的通知方法内被调用。

在这种设计模式中,主题不需要知道观察者的具体类是谁、做了些什么和其他细节,观察者的增加与减少,都不需要更改主题的代码,它做的事就是要将通知发送给所有实现了观察者的对象,达到了松耦合。

看看如何自己实现气象站与布告板的关系:

看完类图再看看气象站和某一个布告板的代码实现:

// 主题 气象站
public class WeatherData implements Subject{
    private ArrayList observers;
    private float temperature; // 气象数据 真实情况是多个
    public WeatherData(){
        observers = new ArrayList();
    }
    public void registerObserver(Observer o){
        observers.add(o);
    }
    public void removeObserver(Observer o){
        int i = observers.indexOf(o);
        if (i >= 0) {
            observers.remove(i);
        }
    }    
    public void notifyObersers(){
        for(int i=0;i<observers.size();i++){
            Observer observer = (Observer)observers.get(i);
            observer.update(temperature);
        }
    }
    public void measurementChanged(){
        notifyObservers();
    }
    public void set measurements(float temperture){
        this.temperture = temperture;
        measurementChanged();
    }
    // 其他方法
}

// 观察者 公布板
public class CurrentConditionsDisplay implents Observer, Displayment{
    private float temperature;
    private Subject weatherData;
    public CurrentConditionsDisplya(Subject weatherData){
        this.weatherData = weatherData;
        // 将自己注册到观察者列表里
        weatherData.registerObserver(this);
    }
    public void update(float temperature){
        this.temperature = temperatrue;
        display();
    }
    public void dispaly(){};  
}

但是可能有个问题,就是目前的数据只有一个temperatrue,如果日后有很多个数据,但是我们的布告板不是都用得到,那在update里将所有数据参数都传进来可能不是一个好办法了,最好能让观察者自己拉数据。

接下来我们使用JAVA内置的观察者模式:Observer接口和Observable类

Observer接口和我们定义的接口类似,而Observable类和我们的Subject差不多:

扩展Observable实现可观察者需要两个步骤:

  1. 先调用setChanged()方法,标记状态已经改变。setChanged()方法可以让我们主动调整通知的频率或时间点,比如我们想一天通知一次,而不是数据一发生变化立即通知。
  2. 调用两种通知方法:notifyObservers()或notifyObservers(Object arg)

观察者接受通知:udpate(Observable o,Ojbect arg),第二个参数对应notifyObservers传的参数,观察者可从Observable中拉去数据,或直接接收notifyObservers推送的数据。

来看看采用了内置的观察者模式的实现代码:

public class WeatherData extends Observable{
    // 不再需要自己管理观察者列表
    private float temperature;
    public WeatherData(){}
    public void measurementsChanged(){
        // 别忘了先更改状态
        setChanged();
        notifyObservers();
    }
    public void setMeasurements(float temperatrue){
        this.temperatrue = temperatrue;
        measurementsChanged();
    }
    // 用于观察者拉取数据
    public float getTemperatrue(){
        return temperatrue;
    }
}

public class CurrentConditionsDisplay immplements Observer, DisplayElement {
    Observable observable;
    private float temperatrue;
    public CurrentConditionsDisplay(Observable observable){
        this.observable = observable;
        // 内置添加观察者的方法
        observable.addObserver(this);
    }
    public void update(Observable obs,Object arg){
        if (obs instanceof WeatherData){
            //....
        }
    }
    // ...    
}

猜你喜欢

转载自blog.csdn.net/weixin_39080782/article/details/82823144