设计模式(二)——行为型设计模式

744 阅读4分钟

观察者模式

定义对象之间的一对多依赖,当一个对象状态改变时,它的所有依赖都会收到通知并且自动更新状态。
主题(Subject)是被观察的对象,而其所有依赖者(Observer)称为观察者。

定义

主题(Subject)具有注册和移除观察者、并通知所有观察者的功能,主题是通过维护一张观察者列表来实现这些操作的。

观察者(Observer)的注册功能需要调用主题的 registerObserver() 方法。

实现方式

天气数据布告板会在天气信息发生改变时更新其内容,布告板有多个,并且在将来会继续增加。

public interface Subject {
    void registerObserver(Observer o);

    void removeObserver(Observer o);

    void notifyObserver();
}
public class WeatherData implements Subject {
    private List<Observer> observers;
    private float temperature;
    private float humidity;
    private float pressure;

    public WeatherData() {
        observers = new ArrayList<>();
    }

    public void setMeasurements(float temperature, float humidity, float pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        notifyObserver();
    }

    @Override
    public void registerObserver(Observer o) {
        observers.add(o);
    }

    @Override
    public void removeObserver(Observer o) {
        int i = observers.indexOf(o);
        if (i >= 0) {
            observers.remove(i);
        }
    }

    @Override
    public void notifyObserver() {
        for (Observer o : observers) {
            o.update(temperature, humidity, pressure);
        }
    }
}

public interface Observer {
    void update(float temp, float humidity, float pressure);
}

public class StatisticsDisplay implements Observer {

    public StatisticsDisplay(Subject weatherData) {
        weatherData.reisterObserver(this);
    }

    @Override
    public void update(float temp, float humidity, float pressure) {
        System.out.println("StatisticsDisplay.update: " + temp + " " + humidity + " " + pressure);
    }
}

public class CurrentConditionsDisplay implements Observer {

    public CurrentConditionsDisplay(Subject weatherData) {
        weatherData.registerObserver(this);
    }

    @Override
    public void update(float temp, float humidity, float pressure) {
        System.out.println("CurrentConditionsDisplay.update: " + temp + " " + humidity + " " + pressure);
    }
}

public class WeatherStation {
    public static void main(String[] args) {
        WeatherData weatherData = new WeatherData();
        CurrentConditionsDisplay currentConditionsDisplay = new CurrentConditionsDisplay(weatherData);
        StatisticsDisplay statisticsDisplay = new StatisticsDisplay(weatherData);

        weatherData.setMeasurements(0, 0, 0);
        weatherData.setMeasurements(1, 1, 1);
    }
}

状态

允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它所属的类。

实现方式

饮料销售机有多种状态,每种状态下销售机有不同的行为,状态可以发生转移,使得销售机的行为也发生改变。

public interface State {
    /**
     * 投币
     */
    void toubi();

    /**
     * 退币
     */
    void tuibi();
}
class SoldOutState implements State{

    @Override
    public void toubi() {
        // doSomething();
    }

    @Override
    public void tuibi() {
        // doSomething();
    }
}

class SoldState implements State{

    @Override
    public void toubi() {
        // doSomething();
    }

    @Override
    public void tuibi() {
        // doSomething();
    }
}
class Machine {

    private State soldOutState;

    private State soldState;

    private State state;
    private int count = 0;

    public Machine(int numberGumballs) {
        count = numberGumballs;
        soldOutState = new SoldOutState();
        soldState = new SoldState();
    }

    public void setState(State state) {
        this.state = state;
    }

    public void releaseBall() {
        System.out.println("A gumball comes rolling out the slot...");
        if (count != 0) {
            count -= 1;
        }
    }

    public State getSoldOutState() {
        return soldOutState;
    }


    public State getSoldState() {
        return soldState;
    }

    public int getCount() {
        return count;
    }

}

策略

定义一系列算法,封装每个算法,并使它们可以互换。
策略模式可以让算法独立于使用它的客户端。

定义

  • Strategy 接口定义了一个算法族,它们都实现了 behavior() 方法。
  • Context 是使用到该算法族的类,其中的 doSomething() 方法会调用 behavior(),setStrategy(Strategy) 方法可以动态地改变 strategy 对象,也就是说能动态地改变 Context 所使用的算法。

与状态模式的比较

状态模式和策略模式类似,并且都是能够动态改变对象的行为。但是状态模式是通过状态转移来改变 Context 所组合的 State 对象,而策略模式是通过 Context 本身的决策来改变组合的 Strategy 对象。所谓的状态转移,是指 Context 在运行过程中由于一些条件发生改变而使得 State 对象发生改变,注意必须要是在运行过程中。

  • 状态模式主要是用来解决状态转移的问题,当状态发生转移了,那么 Context 对象就会改变它的行为
  • 策略模式主要是用来封装一组可以互相替代的算法族(一系列有联系的算法),并且可以根据需要动态地去替换 Context 使用的算法。

实现方式

设计一个鸭子,它可以动态地改变叫声。这里的算法族是鸭子的叫声行为。

public interface QuackBehavior {
    void quack();
}
public class Quack implements QuackBehavior {
    @Override
    public void quack() {
        System.out.println("quack!");
    }
}
public class Squeak implements QuackBehavior{
    @Override
    public void quack() {
        System.out.println("squeak!");
    }
}
public class Duck {

    private QuackBehavior quackBehavior;

    public void performQuack() {
        if (quackBehavior != null) {
            quackBehavior.quack();
        }
    }

    public void setQuackBehavior(QuackBehavior quackBehavior) {
        this.quackBehavior = quackBehavior;
    }
}
public class Client {

    public static void main(String[] args) {
        Duck duck = new Duck();
        duck.setQuackBehavior(new Squeak());
        duck.performQuack();
        duck.setQuackBehavior(new Quack());
        duck.performQuack();
    }
}

模板方法

定义算法框架,并将一些步骤的实现延迟到子类。
通过模板方法,子类可以重新定义算法的某些步骤,而不用改变算法的结构。

实现方式

public abstract class AblstractClass {

    //模板方法用来控制子类的顺序 要想有人生必须按老爸的人生顺序来  
    //声明final不让子类覆盖这个方法,防止改变人生顺序
    public final void 人生(){
        学习();
        工作();
        爱情();
    }
    
    //家里穷更得用工学习
    public void 学习(){
        System.out.println("每天晚上趴在邻居窗上学习");
    }
    
    //工作必须稳定
    public void 工作(){       
        System.out.println("从一而终");
    }
    
    //恋爱自由  让儿子自由恋去
    public abstract void 爱情();

}
public class ConcreteClass extends AblstractClass {
    
    //儿子不认可父亲的学习方法  考高分影响同学关系
    @Override
    public void 学习() {
        System.out.println("60分万岁...");
    }
    
    //父亲给我爱情自由  一定好好谈恋爱
    @Override
    public void 爱情() {
        System.out.println("肤白貌美大长腿...");
    }

}
public class Main {

    public static void main(String[] args) {
         ConcreteClass cs  = new ConcreteClass();
         cs.人生();
    }

}

本文参考CS-Note模板方法设计模式