HeadFirst 设计模式

288 阅读3分钟

《HeadFirst 设计模式》摘抄笔记,供以后查阅。

策略模式

定义

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

设计原则如下:

  • 找出应用中可能变化之处,把他们独立出来,不要和那些不需要变化的代码混在一起
  • 针对接口编程,而不是针对实现编程
  • 多用组合,少用继承

代码演示

不变属性
public abstract class Duck {
    //不变属性可以直接写在超类中

    //动态属性通过组合(has a)方式关联
    private FlyBehavior flyBehavior;
    private QuackBehavior quackBehavior;

    public void performFly(){
        flyBehavior.fly();
    }

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

    public abstract void display();

    //......省略 setter 方法:可以通过该方法动态的设置行为......
}

public class MallardDuck extends Duck {

    public MallardDuck() {
        this.setFlyBehavior(new FlyWithWings());
        this.setQuackBehavior(new Quack());
    }

    @Override
    public void display() {
        System.out.println("MallardDuck.class --> display");
    }
}
动态属性
// 飞翔属性定义
public interface FlyBehavior {
    public void fly();
}

public class FlyWithWings implements FlyBehavior {
    @Override
    public void fly() {
        System.out.println("I'm flying!!!");
    }
}

public class FlyNoWay implements FlyBehavior {
    @Override
    public void fly() {
        System.out.println("I can't fly!!!");
    }
}

// 叫声属性定义
public interface QuackBehavior {
    void quack();
}

public class Quack implements QuackBehavior {
    @Override
    public void quack() {
        System.out.println("Quack");
    }
}

public class MuteQuack implements QuackBehavior {
    @Override
    public void quack() {
        System.out.println("<< Silence >>");
    }
}
执行测试代码
public class DuckDemoMain {
    public static void main(String[] args) {
        MallardDuck mallardDuck = new MallardDuck();
        mallardDuck.performFly();
    }
}

观察者模式

定义

观察者模式定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会通知并自动更新。

设计原则如下:

  • 为了交互对象之间的松耦合设计而努力

核心接口

//主题
public interface Subject {
    //观察者注册为主题的观察者
    void registerObserver(Observer o);
    //观察者将自己在主题观察者列表中移除
    void removeObserver(Observer o);
    //当主题状态改变时,通过该方法通知观察者
    void notifyObserver();
}
//观察者
public interface Observer {
    void update(float temp, float humidity, float pressure);
}

代码演示(推送方式)

场景说明
  • 主题:气象站生成数据
  • 观察者:布告板订阅数据并进行数据展示
代码实现
//业务代码公用行为抽取
public interface DisplayElement {
    //数据展示
    void display();
}

//气象站实现类
public class WeatherData implements Subject {
    private final List<Observer> observerList;
    private float temperature;
    private float humidity;
    private float pressure;

    public WeatherData() {
        this.observerList = new ArrayList<>();
    }

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

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

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

    //数据发生改变执行该动作
    public void measurementsChanged(){
        notifyObserver();
    }

    public void setMeasurements(float temperature,float humidity, float pressure){
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        measurementsChanged();
    }
    //......省略其他方法
}

//布告板实现
public class CurrentConditionsDisplay implements Observer, DisplayElement {
    private float temperature;
    private float humidity;
    private Subject weatherData;

    public CurrentConditionsDisplay(Subject weatherData) {
        this.weatherData = weatherData;
        //在构造方法中进行订阅动作
        weatherData.registerObserver(this);
    }

    @Override
    public void update(float temp, float humidity, float pressure) {
        this.temperature = temp;
        this.humidity = humidity;
        display();
    }

    @Override
    public void display() {
        String msg = String.format("CurrentConditionsDisplay -> temperature:%s、humidity:%s", temperature, humidity);
        System.out.println(msg);
    }
}

//测试类
public class Demo02Maina {
    public static void main(String[] args) {
        WeatherData weatherData = new WeatherData();
        //建立一个或多个公告板
        CurrentConditionsDisplay currentConditionsDisplay = new CurrentConditionsDisplay(weatherData);
        //数据发生改动
        weatherData.setMeasurements(1.0f, 1.0f, 1.0f);
    }
}

Java 内置观察者模式

Java 中内置的观察者模式可以使用推送拉取的方式。

核心接口
//主题:java.util.Observable
public class Observable {
    public synchronized void addObserver(Observer o) {  //......省略代码实现  }
    public synchronized void deleteObserver(Observer o) {  //......省略代码实现  }
    public void notifyObservers() {  
        //......
        if (!changed)
            return;
        //......
    }
    //用来控制粒度,只有将 changed 设置为 true,才会对观察者进行通知
    protected synchronized void setChanged() {
        changed = true;
    }
    //......
}
//观察者:java.util.Observer
public interface Observer {
    void update(Observable o, Object arg);
}
代码实现

对气象站、布告板代码进行重写。

//业务代码公用行为抽取
public interface DisplayElement {
    void display();
}
//气象站
public class WeatherData extends Observable {
    private float temperature;
    private float humidity;
    private float pressure;

    public WeatherData() {
    }

    //数据发生改变执行该动作
    public void measurementsChanged(){
        setChanged();
        notifyObservers();
    }

    public void setMeasurements(float temperature,float humidity, float pressure){
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        measurementsChanged();
    }
    
    //getter 方法用于数据拉取
    public float getTemperature() {
        return temperature;
    }
    public float getHumidity() {
        return humidity;
    }
    public float getPressure() {
        return pressure;
    }
}
//观察者
public class CurrentConditionsDisplay implements Observer, DisplayElement {
    private float temperature;
    private float humidity;
    private Observable observable;

    public CurrentConditionsDisplay(Observable observable) {
        this.observable = observable;
        observable.addObserver(this);
    }

    @Override
    public void update(Observable o, Object arg) {
        if (o instanceof WeatherData) {
            WeatherData weatherData = (WeatherData) o;
            this.temperature = weatherData.getTemperature();
            this.humidity = weatherData.getHumidity();
            display();
        }
    }

    @Override
    public void display() {
        String msg = String.format("CurrentConditionsDisplay -> temperature:%s、humidity:%s", temperature, humidity);
        System.out.println(msg);
    }
}
//测试类
public class Demo03Main {
    public static void main(String[] args) {
        WeatherData weatherData = new WeatherData();
        //建立一个或多个公告板
        CurrentConditionsDisplay currentConditionsDisplay = new CurrentConditionsDisplay(weatherData);
        //数据发生改动
        weatherData.setMeasurements(2.0f, 5.0f, 1.0f);
    }
}