HeadFirst设计模式笔记(一)策略模式,观察者模式

时间:2022-09-09 09:28:13

1. 设计原则

  1. 找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。
  2. 针对接口编程,而不是针对实现编程。
  3. 多样组合,少用继承。
  4. 为了交互对象之间的松耦合设计而努力。
  5. 类应该对扩展开放,而对修改封闭。

2. 设计模式

1. 策略模式

1.1 定义:

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

1.2 鸭子模拟器案例:

HeadFirst设计模式笔记(一)策略模式,观察者模式
这里应用了前两个设计原则。不同鸭子会有不同的飞行行为,不同的鸭子会有不同的呱呱叫行为,这些是需要变化的代码,所以独立出来;把鸭子的飞行行为和呱呱叫行为分别抽象为两个行为接口,设计不同鸭子采用接口不同的实现类。

1.3 示例代码

fly行为
// 飞行接口
public interface FlyBehavior {
public void fly();
}
// 飞
public class FlyWithWings implements FlyBehavior{
public void fly() {
System.out.println("正在用翅膀飞行");
}
}
// 不飞
public class FlyNoWay implements FlyBehavior{
public void fly() {
System.out.println("不会飞");
}
}
//坐火箭飞
public class FlyRocketPowered implements FlyBehavior{
public void fly() {
System.out.println("坐火箭飞");
}
}
quack行为
// 叫接口
public interface QuackBehavior {
public void quack();
}
// 嘎嘎叫
public class Quack implements QuackBehavior. {
public void quack() {
System.out.println("嘎嘎叫");
}
}
// 吱吱叫
public class Squeak implements QuackBehavior{
public void quack() {
System.out.println("吱吱叫");
}
}
// 不叫
public class MuteQuack implements QuackBehavior{
public void quack() {
System.out.println("不会叫");
}
}
实现Duck类
// 鸭子超类
public abstract class Duck {
// 默认的行为
FlyBehavior flyBehavior;
QuackBehavior quackBehavior;

public Duck() {
}
public void setFlyBehavior(FlyBehavior. fb) {
flyBehavior = fb;
}
public void setQuackBehavior(QuackBehavior. qb) {
quackBehavior = qb;
}
abstract void display();
public void performFly() {
flyBehavior.fly();
}
public void performQuack() {
quackBehavior.quack();
}
public void swim() {
System.out.println("正在游泳~~");
}
}

// 野鸭
public class MallardDuck extends Duck {
public MallardDuck() {
quackBehavior = new Quack();
flyBehavior = new FlyWithWings(); //这里也可以使用setFlyBehavior方法,下同!
}
public void display() {
System.out.println("绿头鸭");
}
}
// 红头鸭
public class RedHeadDuck extends Duck {
public RedHeadDuck() {
flyBehavior = new FlyWithWings();
quackBehavior = new Quack();
}
public void display() {
System.out.println("红头鸭");
}
}
// 橡皮鸭
public class RubberDuck extends Duck {
public RubberDuck() {
flyBehavior = new FlyNoWay();
quackBehavior = new Squeak();
}
public void display() {
System.out.println("橡皮鸭");
}
}
//模型鸭
public class ModelDuck extends Duck {
public ModelDuck() {
flyBehavior = new FlyNoWay();
quackBehavior = new Quack();
}
public void display() {
System.out.println("模型鸭");
}
}

/*测试代码:*/

public class MiniDuckSimulator {

public static void main(String[] args) {

MallardDuck mallard = new MallardDuck();
RubberDuck rubberDuckie = new RubberDuck();
RedHeadDuck redHeadDuck = new RedHeadDuck();

ModelDuck model = new ModelDuck();

mallard.performQuack();
rubberDuckie.performQuack();
redHeadDuck.performQuack();

model.performFly();
model.setFlyBehavior(new FlyRocketPowered());
model.performFly();
}
}

2. 观察者模式

2.1 定义:

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

2.2 气象站发布气象布告栏订阅信息显示案例:

HeadFirst设计模式笔记(一)策略模式,观察者模式
这里气象站是主题(Subject,或者叫做Observabler)类比于出版者,是事件发生的主体,布告栏是订阅者改称为观察者(Observer),是响应事情发生的主体。这里是一个一对多关系。模式定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新,这样的模式让主题和观察者之间松耦合。它体现了第四个原则:为了交互对象之间的松耦合设计而努力。

2.3.1 首先定义接口,实现这两个接口的类就是相应的主题类–气象搜集装置以及观察者类–对应气象发布版:

// 在主题接口中定义注册删除通知观察者三个方法
public interface Subject {
public void registerObserver(Observer o);
public void removeObserver(Observer o);
public void notifyObservers();
}
// 在观察者中,我们要求有一个方法:更新气象发布版的数据。
public interface Observer {
public void update(float temp, float humidity, float pressure);
}
// 另外,每个布告板需要显示信息,定义第三个显示接口
public interface DisplayElement {
public void display();
}

2.3.2 接口实现以及测试

public class WeatherData implements Subject { 
private ArrayList observers;//维护一个观察者列表
private float temperature;
private float humidity;
private float pressure;
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 notifyObservers() { //这个方法对所有注册的观察者进行通知
for (int i = 0; i < observers.size(); i++) {
Observer observer = (Observer)observers.get(i);
observer.update(temperature, humidity, pressure); //推数据
}
}
public void measurementsChanged() { //这个方法是对notifyObservers的封装
notifyObservers();
}
public void setMeasurements(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
measurementsChanged();//这个方法会进而去通知所有的观察者
}
// other WeatherData methods here
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 Subject weatherData;//维护一个主题的引用,注册观察者所用
public CurrentConditionsDisplay(Subject weatherData) {
this.weatherData = weatherData;
weatherData.registerObserver(this);//创建的时候就注册,这里也可以不进行这个,而使用 WeatherData 的registerObserver公有方法
}
public void update(float temperature, float humidity, float pressure) { //观察者留出的推送接口
this.temperature = temperature;
this.humidity = humidity;
display();
}
public void display() {
System.out.println("Current conditions: " + temperature
+ "F degrees and " + humidity + "% humidity");
}
}

/*我们测试一下这个程序:*/
public class WeatherStation {
public static void main(String[] args) {
WeatherData weatherData = new WeatherData();
CurrentConditionsDisplay currentDisplay =
new CurrentConditionsDisplay(weatherData);
StatisticsDisplay statisticsDisplay = new StatisticsDisplay(weatherData);
ForecastDisplay forecastDisplay = new ForecastDisplay(weatherData);
weatherData.setMeasurements(80, 65, 30.4f);
weatherData.setMeasurements(82, 70, 29.2f);
weatherData.setMeasurements(78, 90, 29.2f);
}
}

2.3.3 java内置观察者模式

java内置的主题是一个类:Observable
java内置的观察者是接口:Observer