观察者模式
定义对象之间的一对多依赖,当一个对象状态改变时,它的所有依赖都会收到通知并且自动更新状态。
主题(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.人生();
}
}