状态模式

状态模式允许对象在内部状态改变时改变其行为, 使得对象在不同的状态下有不同的行为表现. 通过将每个状态封装成独立的类, 可以避免使用大量的条件语句实现状态切换

状态模式结构

  • 状态接口: 声明行为方法
  • 具体状态类: 实现状态接口, 封装具体行为
  • 上下文类: 维护一个状态对象, 并提供方法以改变其状态

状态模式实现

// 状态接口
public interface State {
public doAction(Context context);
}

// 实现状态接口的实体类
public class StartState implements State {
public void doAction(Context context) {
System.out.println("Player is in start state");
context.setState(this);
}
}

public class StopState implements State {
public void doAction(Context context) {
System.out.println("Player is in stop state");
context.setState(this);
}
}

// 上下文类
public class Context {
private State state;

public Context() {
state = null;
}

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

public State getState() {
return state;
}
}

public class Client {
public static void main(String[] args) {
Context context = new Context();
State startState = new StartState();
startState.doAction(context);

State stopState = new StopState();
stopState.doAction(context);
}
}

优点:

  • 封装状态转换规则: 将状态转换逻辑封装在状态对象内部
  • 易于拓展: 增加新的状态类不会影响现有的代码
  • 集中状态相关的行为: 状态相关的行为都集中在了状态类
  • 简化代码: 避免使用了复杂的条件代码来切换行为
  • 状态共享: 允许多个上下文对象共享同一个状态

缺点:

  • 增加类的数量: 每个状态都要一个具体的状态类
  • 实现复杂: 状态模式的实现比较复杂
  • 开闭原则支持不足: 修改状态行为可能需要修改现有代码

观察者模式

观察者模式定义了一对多的依赖关系, 当一个对象的状态发生变化时, 其依赖者都会收到通知并自动更新

观察者模式结构

  • 观察者接口: 包含一个观察者更新的方法
  • 具体观察者: 实现观察者接口, 定义接收到通知时的行为
  • 主题接口: 包含添加, 删除, 通知观察者的方法
  • 具体主题: 实现主题接口, 通知观察者

观察者模式实现

// 主题
public class Subject {
private List<Observer> observers = new ArrayList<>();
private int state;

public int getState() {
return state;
}

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

public void attach(Observer observer) {
observers.add(observer);
}

public void notifyAllObservers() {
for (Observer observer : observers) {
observer.update();
}
}
}

// 观察者接口
public interface Observer {
protected Subject subject;
public void update();
}

// 实体观察者类
public class BinaryObserver {
public BinaryObserver(Subject subject) {
this.subject = subject;
this.subject.attach(this);
}

@Override
public void update() {
System.out.println("Binary String: " + Integer.toBinaryString(subject.getState()));
}
}

public class OctalObserver {
public OctalObserver(Subject subject) {
this.subject = subject;
this.subject.attach(this);
}

@Override
public void update() {
System.out.println("Octal String: " + Integer.toOctalString(subject.getState()));
}
}

public class HexaObserver {
public HexaObserver(Subject subject) {
this.subject = subject;
this.subject.attach(this);
}

@Override
public void update() {
System.out.println("Hex String: " + Integer.toHexString(subject.getState()).toUpperCase());
}
}

public class Client {
public static void main(String[] args) {
Subject subject = new Subject();
new BinaryObserver(subject);
new OctalObserver(subject);
new HexaObserver(subject);

subject.setState(15);
subject.setState(10);
}
}

优点:

  • 抽象耦合: 观察者和主题之间是抽象耦合的
  • 触发机制: 建立了一套状态改变时的触发和通知机制

缺点:

  • 性能问题: 如果观察者众多, 通知过程可能耗时
  • 循环依赖: 可能导致循环调用
  • 缺乏变换详情: 观察者不知道主题如何变化, 只知道变化发生

中介者模式

中介者模式定义了一个中介对象来封装一系列对象之间的交互. 中介者使各对象之间不需要显式地相互引用, 从而使其耦合松散, 且可以独立地改变它们之间的交互

中介者模式结构

  • 中介者接口: 规定中介者必须实现的接口
  • 具体中介者: 实现中介者接口
  • 定义同事类:各个对象不需要显式地相互引用, 而是通过中介者来进行交互

中介者模式实现

// 中介类
public class ChatRoom {
public static void showMessage(User user, String message){
System.out.println(new Date().toString()
+ " [" + user.getName() +"] : " + message);
}
}

// 同事类
public class User {
private String name;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public User(String name){
this.name = name;
}

public void sendMessage(String message){
ChatRoom.showMessage(this,message);
}
}

public class Client {
public static void main(String[] args) {
User robert = new User("Robert");
User john = new User("John");

robert.sendMessage("Hi! John!");
john.sendMessage("Hello! Robert!");
}
}

优点:

  • 降低复杂度: 将对象间一对多的关系转换为一对一关系
  • 解耦: 对象之间不再直接引用, 通过中介者进行交互
  • 符合迪米特原则: 对象只需要知道中介者, 不需要知道其他对象

缺点:

  • 可能会变得复杂, 难以维护