java设计模式[4]之设计型模式
文章目录
- 零 行为型模式概述
- 一 观察者模式
- 1.1 观察者模式的核心角色
- 1.2 观察者模式的实现代码
- 1.2.1 定义观察者接口
- 1.2.2 定义被观察者接口
- 1.2.3 实现具体的被观察者
- 1.2.4实现具体的观察者
- 1.2.5 测试用例
- 1.3 观察者模式的优缺点
- 1.4 观察者模式的应用场景
- 二 模版方法模式
- 2.1 模版方法模式的核心思想
- 2.2 模版方法模式的核心角色
- 2.3 模版方法模式的实现代码
- 2.3.1 抽象类 `GameTemplate`
- 2.3.2 具体类 `FootballGame`
- 2.3.3 具体类 `ChessGame`
- 2.3.4 测试用例
- 2.4 模版方法模式的优缺点
- 2.5 模版方法模式的应用场景
- 三 策略模式
- 3.1 策略模式的核心思想
- 3.2 策略模式的核心角色
- 3.3 策略模式的实现
- 3.3.1 策略接口:`PaymentStrategy`
- 3.3.2 具体策略类`CreditCardPayment`和`PayPalPayment`
- 3.3.3 上下文类:`ShoppingCart`
- 3.3.4 测试用例
- 3.4 策略模式的优缺点
- 3.5 策略模式的适用场景
- 3.6 策略模式的经典应用
- 3.7 和其他模式对比
- 四 责任链模式
- 4.1 责任链模式的核心思想
- 4.2 责任链模式的核心角色
- 4.3 责任链模式的实现代码
- 4.3.1 数组方式
- 4.3.2 链表方式
- 4.4 责任链模式的优缺点
- 4.5 责任链模式的应用场景
- 五 状态模式
- 5.1 状态模式的核心角色
- 5.2 状态模式的使用场景
- 5.3 状态模式的优缺点
- 5.4 状态模式的代码实现
- 5.4.1 定义状态接口
- 5.4.2 具体状态类
- 5.4.3 上下文类
- 5.4.4 使用示例
- 5.5 状态模式的状态机
- 5.5.1 状态机分支判断法
- 5.5.2 查表法
- 5.5.3 状态模式
- 六 迭代器模式
- 6.1 迭代器模式的核心角色
- 6.2 迭代器模式的实现代码
- 6.3 迭代器模式的优点
- 6.4 迭代器模式的适用场景
- 6.5 迭代器模式的Java 内置支持
- 七 访问者模式
- 7.1 访问者模式的核心思想
- 7.2 访问者模式的核心角色
- 7.3 访问者模式的代码实现
- 7.4 访问者模式的使用场景
- 7.5 访问者模式的优缺点
- 八 备忘录模式
- 8.1 备忘录模式的核心思想
- 8.2 备忘录模式的核心角色
- 8.3 备忘录模式的代码实现
- 8.4 备忘录模式的优缺点
- 8.5 备忘录模式的应用场景
- 九命令模式
- 9.1 命令模式的核心角色
- 9.2 命令模式的代码实现
- 9.3 命令模式的优点
- 9.4 命令模式的适用场景
- 十 解释器模式
- 10.1 解释器模式的核心角色
- 10.2 解释器模式的代码实现
- 10.3 解释器模式的优缺点
- 10.4 解释器模式的适用场景
- 10.5 解释器模式的实际应用
- 十一 中介模式
- 11.1 中介者模式的核心角色
- 11.2 终结者模式的代码实现
- 11.3 中介者模式的应用场景
- 11.4 中介者模式的优缺点
- 11.5 中介者模式的适用性

零 行为型模式概述
- 行为型模式关注的是对象之间的通信,也就是描述多个类或者对象之间,通过协作共同完成一个任务。主要涉及对象和算法之间的职责分配。
- 行为型模式分为两类:
- 类行为模式:通过继承机制来在类间分派行为,主要通过多态来分类父类和子类的职责。
- 对象行为模式:通过组合或聚合,在对象间分配行为。通过对象关联等方式来分类类的职责。
一 观察者模式
- 观察者模式(Observer Pattern)是一种行为型设计模式,它定义了对象之间的一对多依赖关系,当一个对象的状态发生变化时,所有依赖它的对象都会自动收到通知并更新。在这个场景中,发生改变的对象称为观察目标,被通知的对象称为观察者。一个观察目标可以有过个观察者,而这些观察者之间没有联系,可以根据需要增减。
- 观察者模式又称为发布/订阅(Publish/Subscribe)模式,在对象之间定义了一对多的依赖。当一个对象改变状态,依赖它的对象会收到通知并自动更新。
1.1 观察者模式的核心角色
Subject
(被观察者/主题):维护观察者列表,并提供注册、移除和通知观察者的方法。Observer
(观察者):定义一个更新接口,用于在被观察者状态变化时接收通知。ConcreteSubject
(具体被观察者):实现主题接口,保存状态信息,在状态变化时通知所有观察者。ConcreteObserver
(具体观察者):实现更新方法,响应被观察者的状态变化。
1.2 观察者模式的实现代码
1.2.1 定义观察者接口
public interface Observer {void update(String message);
}
1.2.2 定义被观察者接口
import java.util.List;
import java.util.ArrayList;public interface Subject {void registerObserver(Observer observer);void removeObserver(Observer observer);void notifyObservers(String message);
}
1.2.3 实现具体的被观察者
public class ConcreteSubject implements Subject {private List<Observer> observers = new ArrayList<>();@Overridepublic void registerObserver(Observer observer) {observers.add(observer);}@Overridepublic void removeObserver(Observer observer) {observers.remove(observer);}@Overridepublic void notifyObservers(String message) {for (Observer observer : observers) {observer.update(message);}}// 模拟状态变化并通知观察者public void someBusinessLogic() {System.out.println("Subject: 发生了某些业务逻辑变化");notifyObservers("状态已更新!");}
}
1.2.4实现具体的观察者
public class ConcreteObserver implements Observer {private String name;public ConcreteObserver(String name) {this.name = name;}@Overridepublic void update(String message) {System.out.println(name + " 收到通知: " + message);}
}
1.2.5 测试用例
public class Client {public static void main(String[] args) {ConcreteSubject subject = new ConcreteSubject();Observer observer1 = new ConcreteObserver("观察者1");Observer observer2 = new ConcreteObserver("观察者2");subject.registerObserver(observer1);subject.registerObserver(observer2);subject.someBusinessLogic();subject.removeObserver(observer1);subject.someBusinessLogic();}
}
- 执行结果
Subject: 发生了某些业务逻辑变化 观察者1 收到通知: 状态已更新! 观察者2 收到通知: 状态已更新! Subject: 发生了某些业务逻辑变化 观察者2 收到通知: 状态已更新!
1.3 观察者模式的优缺点
优点
- 解耦:被观察者和观察者之间是松耦合的,它们可以属于不同的模块或层级。
- 可扩展性:新增观察者无需修改被观察者代码,符合开闭原则。
- 支持广播通信:被观察者状态变化后会自动通知所有观察者。
缺点
- 性能问题(观察者过多):当观察者数量较多或更新逻辑复杂时,通知过程可能造成性能瓶颈。特别是在同步调用场景下,可能阻塞主线程。
- 内存泄漏风险:如果观察者未及时注销(unregister),可能导致内存泄漏。尤其在长期运行的对象作为观察者时,需手动管理生命周期。
- 顺序和依赖不确定:观察者的执行顺序通常不明确,若业务逻辑对顺序敏感,可能导致不可预期行为。各观察者之间不应有强依赖关系,否则难以维护。
- 复杂度上升:随着观察者数量和逻辑增多,系统复杂度提升,调试和维护难度增加。可能出现“链式通知”或“循环依赖”,导致系统不稳定。
- 异常传播风险:某个观察者的 update() 方法抛出异常,可能中断后续观察者的执行流程。需要额外处理异常隔离机制。
- 过度设计:对于简单的一对一通信场景,使用观察者模式可能显得冗余,增加不必要的抽象层级。
1.4 观察者模式的应用场景
- 事件监听机制(如 GUI 中的按钮点击)
- MVC 架构中模型与视图之间的同步
- 订阅-发布系统
- 数据变更通知
二 模版方法模式
- 模板方法模式(Template Method Pattern)是行为型设计模式之一,它定义了一个操作中的算法骨架,而将一些步骤延迟到子类中实现。模板方法使得子类可以在不改变算法结构的前提下,重新定义算法中的某些步骤。
2.1 模版方法模式的核心思想
- 定义一个抽象类(Abstract Class):其中包含一个模板方法和若干基本方法。
- 模板方法(Template Method):定义算法的骨架,通常是一个具体方法,调用多个基本方法。
- 基本方法(Primitive Methods):可以是抽象方法(由子类实现),也可以是钩子方法(Hook Method),提供默认实现,子类可选择性覆盖。
2.2 模版方法模式的核心角色
角色 | 职责 |
---|---|
AbstractClass | 定义抽象类,声明模板方法和基本方法(包括抽象方法和钩子方法) |
ConcreteClass | 实现抽象类中的抽象方法,可以覆盖钩子方法 |
2.3 模版方法模式的实现代码
2.3.1 抽象类 GameTemplate
public abstract class GameTemplate {// 模板方法,定义了算法骨架public final void play() {initialize();startGame();endGame();}// 基本方法 - 初始化protected abstract void initialize();// 基本方法 - 开始游戏protected abstract void startGame();// 钩子方法 - 可选实现protected void endGame() {System.out.println("Game ended.");}
}
2.3.2 具体类 FootballGame
public class FootballGame extends GameTemplate {@Overrideprotected void initialize() {System.out.println("Football game initialized.");}@Overrideprotected void startGame() {System.out.println("Football match started.");}
}
2.3.3 具体类 ChessGame
public class ChessGame extends GameTemplate {@Overrideprotected void initialize() {System.out.println("Chess game initialized.");}@Overrideprotected void startGame() {System.out.println("Chess match started.");}@Overrideprotected void endGame() {System.out.println("Chess game ended with checkmate.");}
}
2.3.4 测试用例
public class Client {public static void main(String[] args) {GameTemplate football = new FootballGame();football.play();GameTemplate chess = new ChessGame();chess.play();}
}
2.4 模版方法模式的优缺点
优点:
- 封装不变部分,扩展可变部分:算法骨架固定,子类只需实现变化的部分。
- 提高代码复用性:公共逻辑在父类中实现,避免重复代码。
- 符合开闭原则:新增子类不影响已有逻辑。
缺点:
- 增加子类复杂度:每个不同实现都需要一个子类。
- 违反里氏替换原则(LSP)风险:如果钩子方法被错误重写,可能影响整体流程。
2.5 模版方法模式的应用场景
JdbcTemplate
中的execute()
方法即为模板方法。Servlet
中的doGet()
/doPost()
是钩子方法。Spring
框架中大量使用模板方法模式,如JmsTemplate
,RestTemplate
等。
三 策略模式
- 策略模式(Strategy Pattern)是一种行为型设计模式,它定义了一系列算法,并将每个算法封装起来,使它们可以互相替换。策略模式让算法的变化独立于使用它的客户端。
3.1 策略模式的核心思想
- 将算法或行为封装为独立的类。客户端通过统一接口调用不同的实现,从而实现算法的动态切换。
3.2 策略模式的核心角色
角色 | 职责 |
---|---|
Strategy 接口 | 定义算法公共操作,是策略的抽象 |
ConcreteStrategy 类 | 实现具体算法 |
Context 类 | 持有一个策略对象的引用,最终调用策略 |
3.3 策略模式的实现
3.3.1 策略接口:PaymentStrategy
public interface PaymentStrategy {void pay(int amount);
}
3.3.2 具体策略类CreditCardPayment
和PayPalPayment
public class CreditCardPayment implements PaymentStrategy {@Overridepublic void pay(int amount) {System.out.println("Paid " + amount + " via Credit Card.");}
}
public class PayPalPayment implements PaymentStrategy {@Overridepublic void pay(int amount) {System.out.println("Paid " + amount + " via PayPal.");}
}
3.3.3 上下文类:ShoppingCart
public class ShoppingCart {private PaymentStrategy paymentStrategy;public void setPaymentStrategy(PaymentStrategy paymentStrategy) {this.paymentStrategy = paymentStrategy;}public void checkout(int totalAmount) {if (paymentStrategy != null) {paymentStrategy.pay(totalAmount);} else {System.out.println("No payment strategy set.");}}
}
3.3.4 测试用例
public class Client {public static void main(String[] args) {ShoppingCart cart = new ShoppingCart();// 设置支付策略为信用卡支付cart.setPaymentStrategy(new CreditCardPayment());cart.checkout(100); // 输出: Paid 100 via Credit Card.// 切换为PayPal支付cart.setPaymentStrategy(new PayPalPayment());cart.checkout(200); // 输出: Paid 200 via PayPal.}
}
3.4 策略模式的优缺点
优点
- 解耦:客户端与具体算法解耦。
- 扩展性强:新增策略只需添加新类,符合开闭原则。
- 易于替换:运行时可动态切换策略。
缺点
- 策略类数量多时,可能增加系统复杂度。
- 所有策略类都需要对外暴露。
3.5 策略模式的适用场景
- 多种相似算法或行为需要在运行时动态切换。
- 用于替代多重条件判断语句。
- 需要隐藏算法实现细节的场合。
3.6 策略模式的经典应用
- 数据验证:Spring框架提供Validator接口,允许开发者定义验证规则。通过实现不同的验证策略(如电子邮件验证,值范围验证等),可以在不同场景中使用不同的验证器,提高代码的复用性和灵活性。
- 缓存管理:Spring Cache提供Cache接口,允许开发者定义缓存策略,可以实现不同的缓存策略(如LRU缓存,FIFO缓存),并在服务方法中使用
@Cacheable
注解来指定缓存策略,从而在不修改业务逻辑的情况下优化系统性能。 - 事务处理:Spring容器提供事务管理服务,允许开发者定义不同的事务策略,并在服务方法中使用
@Transactional
注解来指定事务策略,方便开发者在不同业务场景下灵活选择处理事务的方式。 - 依赖注入:Spring提供DI规范,允许开发者使用
@Autowird
注解将依赖注入类中。通过定义不同的依赖注入策略,实现在不修改代码的情况下灵活地管理依赖关系。 - 多种算法选择:策略模式还常用于动态选择多种算法的场景。如,在支付系统中,不同的支付方式可以对应不同的结算方法;在物流系统中,不同的车型可能对应不同的物流规则。通过定义抽象策略和具体策略类,可以在运行时根据需求选择合适的算法进行处理。
- 场景模式:在场景模拟中,如游戏开发、仿真实验等。根据不同的条件选择不同的算法或行为。策略模式可以将这些算法或行为封装成独立的策略类,并在运行时根据条件动态选择使用策略类。
3.7 和其他模式对比
模式 | 区别 |
---|---|
状态模式 | 策略模式是无状态的,而状态模式内部维护状态变化 |
模板方法 | 模板方法是通过继承固定流程,策略是通过组合方式改变行为 |
四 责任链模式
- 责任链模式(Chain of Responsibility Pattern)是行为型设计模式之一,它允许将请求沿着处理者对象链进行传递,并让每个处理者决定是否处理该请求。这种方式实现了请求的发送者和接收者之间的解耦。
- 责任链模式适用于请求的处理流程不确定或需要动态配置的场景,能够有效实现请求与处理者的解耦,提升系统的灵活性和可维护性。
4.1 责任链模式的核心思想
- 解耦请求发送者和处理者:发送者无需知道具体处理者,只需要将请求发送到链上的第一个节点。
- 动态调整处理逻辑:通过改变链的结构,可以灵活地增加、删除或修改请求的处理逻辑。
4.2 责任链模式的核心角色
- Handler(抽象处理者):定义一个处理请求的接口,通常包含一个指向下一个处理者的引用。
- ConcreteHandler(具体处理者):实现具体的请求处理逻辑,如果自己无法处理,则转发给下一个处理者。
- Client(客户端):创建请求并将其提交给链上的第一个处理者。
4.3 责任链模式的实现代码
4.3.1 数组方式
// 责任链模式 基于数组的方式实现
public interface Handler {boolean handle();
}public class HandlerA implements Handler {@Overridepublic boolean handle() {boolean handle = false;//结合自身处理逻辑判断是否需要处理System.out.println("处理A……");return false;}
}public class HandlerB implements Handler {@Overridepublic boolean handle() {boolean handle = false;//结合自身处理逻辑判断是否需要处理System.out.println("处理B……");return false;}
}public class HandlerC implements Handler {@Overridepublic boolean handle() {boolean handle = false;//结合自身处理逻辑判断是否需要处理System.out.println("处理C……");return false;}
}/*** 责任链*/
public class HandlerChain {private List<Handler> handlers = new ArrayList<>();public void addHandler(Handler handler) {handlers.add(handler);}public void handle() {for (Handler handler : handlers) {boolean handled = handler.handle() ;if (handled) {break;}}}
}public class Client {public static void main(String[] args) {HandlerChain handlerChain = new HandlerChain();handlerChain.addHandler(new HandlerA());handlerChain.addHandler(new HandlerB());handlerChain.handle();}
}
4.3.2 链表方式
//责任链中处理器的父类
public abstract class Handler {//持有下一个处理器的引用protected Handler nextHandler=null;// 持有下一个处理器的引用public void setSuccessor(Handler successor) {this.nextHandler=successor;}// 定义抽象处理方法protected abstract boolean doHandle();// 定义一个处理业务的方法public final void handle() {//让具体的处理器处理boolean isHandle = doHandle();// 如果没有处理,则将请求传递给下一个处理if(!isHandle && nextHandler!=null) {nextHandler.handle();}}
}public class HandlerA extends Handler{@Overrideprotected boolean doHandle() {boolean handle = false;//结合自身处理逻辑判断是否需要处理System.out.println("处理A……");return false;}
}public class HandlerB extends Handler{@Overrideprotected boolean doHandle() {boolean handle = false;//结合自身处理逻辑判断是否需要处理System.out.println("处理B……");return false;}
}public class HandlerC extends Handler{@Overrideprotected boolean doHandle() {boolean handle = false;//结合自身处理逻辑判断是否需要处理System.out.println("处理C……");return false;}
}/*** 责任链*/
public class HandlerChain {private Handler head = null;private Handler tail = null;public void addHandler(Handler handler){handler.setSuccessor(null);if(head == null){head = handler;tail = handler;}else{tail.setSuccessor(handler);tail = handler;}}/*** 执行链路执行*/public void handle(){if(head != null){head.handle();}}
}public class Client {public static void main(String[] args) {HandlerChain handlerChain = new HandlerChain();handlerChain.addHandler(new HandlerA());handlerChain.addHandler(new HandlerB());handlerChain.handle();}
}
4.4 责任链模式的优缺点
优点
- 降低耦合度:请求的发送者不需要知道具体的处理者,只需将请求发送到链上即可。
- 增强系统的可扩展性:可以灵活地添加、修改或移除处理者。
- 符合开闭原则:增加新的处理者时,无需修改现有代码。
缺点
- 性能问题:如果链过长或处理逻辑复杂,可能会影响性能。
- 请求可能未被处理:如果链中没有合适的处理者,请求可能会被丢弃而不做任何处理。
4.5 责任链模式的应用场景
- 审批流程:例如请假申请需要多级审批,每一级根据权限判断是否处理。
- 过滤器链:如 Web 请求经过多个拦截器进行日志记录、身份验证等。
- 异常处理机制:不同层级的异常处理器按优先级依次尝试处理异常。
五 状态模式
- 状态模式(State Pattern)是行为型设计模式之一,它允许对象在其内部状态改变时改变其行为。该模式将状态相关的行为封装到独立的状态类中,使得对象的状态变化更加清晰和可维护。
- 状态模式允许一个对象基于其内部状态来改变行为,看起来像是修改了自身的类。
5.1 状态模式的核心角色
- Context(上下文):拥有状态的对象,维护一个对
State
接口的引用,通过委托给当前状态对象来处理请求。 - State(状态接口):定义状态相关的公共行为,通常是一个接口或抽象类。
- ConcreteState(具体状态类):实现与特定状态相关的行为。
5.2 状态模式的使用场景
- 对象的行为依赖于其状态,并且需要在运行时根据状态动态调整行为。
- 避免大量条件判断语句(如
if-else
或switch-case
)导致代码难以维护。 - 状态转换逻辑复杂,需要清晰地分离各个状态行为。
5.3 状态模式的优缺点
优点
- 消除冗长的条件判断:将状态逻辑分散到各个状态类中,提高代码可读性和可维护性。
- 开闭原则:增加新的状态只需扩展,不需修改已有代码。
- 职责分离:每个状态类只处理自身逻辑,符合单一职责原则。
缺点
- 如果状态较少或逻辑简单,引入状态模式可能导致类数量增多、结构复杂。
- 状态转换逻辑如果过于复杂,可能需要额外管理状态之间的关系。
5.4 状态模式的代码实现
5.4.1 定义状态接口
public interface State {void handle(Context context);
}
5.4.2 具体状态类
public class ConcreteStateA implements State {@Overridepublic void handle(Context context) {System.out.println("当前状态为 A,执行操作...");context.setState(new ConcreteStateB());}
}public class ConcreteStateB implements State {@Overridepublic void handle(Context context) {System.out.println("当前状态为 B,执行操作...");context.setState(new ConcreteStateA());}
}
5.4.3 上下文类
public class Context {private State state;public Context(State initialState) {this.state = initialState;}public void setState(State state) {this.state = state;}public void request() {state.handle(this);}
}
5.4.4 使用示例
public class Client {public static void main(String[] args) {Context context = new Context(new ConcreteStateA());context.request(); // 输出 "当前状态为 A,执行操作...",切换为 Bcontext.request(); // 输出 "当前状态为 B,执行操作...",切换为 A}
}
5.5 状态模式的状态机
- 状态模式中的状态机分为3种:分支判断、查表法和状态模式。通过《超级马里奥》这款游戏进行介绍,马里奥可以变身成为多种状态:小马里奥(Small Mario)、超级马里奥(Super Mario)、火焰马里奥(Fire Mario)、斗篷马里奥(Cape Mario)。在不同的情节中各个形态会互相转换,并相应的增减积分,示意图如下:
符号 | 含义 |
---|---|
E1 | 吃了蘑菇 |
E2 | 获得斗篷 |
E3 | 获得火焰 |
E4 | 碰到怪物 |
5.5.1 状态机分支判断法
// 状态枚举类
public enum State {SMALL(0),SUPER(1),FIRE(2),CAPE(3);private int value;State(int value) {this.value = value;}public int getValue() {return this.value;}
}// 马里奥的状态机
public class MarioStateMachine {private int score; // 分数private State currentState;// 当前状态public MarioStateMachine() {this.score = 100;this.currentState = State.SMALL;}/*** 获得蘑菇*/public void obtainMushRoom() {if (currentState == State.SMALL) {currentState = State.SUPER;score += 100;}}public void lossMushRoom() {if (currentState == State.SUPER) {currentState = State.SMALL;score -= 100;}}/*** 获得斗篷*/public void obtainCape() {if (currentState == State.SMALL || currentState == State.SUPER) {currentState = State.CAPE;score += 200;}}public void lossCape() {if (currentState == State.CAPE) {currentState = State.SMALL;score -= 200;}}/*** 获得火焰*/public void obtainFire() {if (currentState == State.SMALL || currentState == State.SUPER) {currentState = State.FIRE;score += 300;}}public void lossFire() {if (currentState == State.FIRE) {currentState = State.SMALL;score -= 300;}}/*** 遇到怪物*/public void meetMonster() {if (currentState == State.FIRE) {currentState = State.SMALL;score -= 100;} else if (currentState == State.CAPE) {currentState = State.SMALL;score -= 200;} else if (currentState == State.SUPER) {currentState = State.SMALL;}}public int getScore() {return score;}public State getCurrentState() {return currentState;}}//测试用例
public class AppStart {public static void main(String[] args) {MarioStateMachine marioStateMachine = new MarioStateMachine();marioStateMachine.obtainMushRoom();System.out.println("当前分数:" + marioStateMachine.getScore()+" 当前状态:"+marioStateMachine.getCurrentState());marioStateMachine.obtainCape();System.out.println("当前分数:" + marioStateMachine.getScore()+" 当前状态:"+marioStateMachine.getCurrentState());marioStateMachine.meetMonster();System.out.println("当前分数:" + marioStateMachine.getScore()+" 当前状态:"+marioStateMachine.getCurrentState());}
}
5.5.2 查表法
符号 | 含义 |
---|---|
E1 | 吃了蘑菇 |
E2 | 获得斗篷 |
E3 | 获得火焰 |
E4 | 碰到怪物 |
//马里奥的角色状态
public enum State {SMALL(0),SUPER(1),FIRE(2),CAPE(3);private int value;State(int value) {this.value = value;}public int getValue() {return this.value;}
}// 事件枚举
public enum Event {OBTAIN_MUSHROOM(0),OBTAIN_CAPE(1),OBTAIN_FIRE(2),MEET_MONSTER(3);private int value;Event(int value){this.value = value;}public int getValue(){return this.value;}
}// 状态机
public class MarioStateMachine {private int score;private State currentState;public MarioStateMachine() {this.score = 100;this.currentState = State.SMALL;}//定义状态和积分的二维数组private static final State[][] transitionTable = {{State.SUPER, State.CAPE, State.FIRE, State.SMALL},{State.SUPER, State.CAPE, State.FIRE, State.SMALL},{State.CAPE, State.CAPE, State.CAPE, State.SMALL},{State.FIRE, State.FIRE, State.FIRE, State.SMALL},};private static final int[][] actionTable = {{100, 200, 300, 0},{0, 200, 300, -100},{0, 0, 0, -200},{0, 0, 0, -300},};public void obtainMushRoom(){executeEvent(Event.OBTAIN_MUSHROOM);}public void obtainCape(){executeEvent(Event.OBTAIN_CAPE);}public void obtainFire(){executeEvent(Event.OBTAIN_FIRE);}public void meetMonster(){executeEvent(Event.MEET_MONSTER);}public int getScore() {return score;}public State getCurrentState() {return currentState;}public void executeEvent(Event event) {int stateValue = currentState.getValue();int eventValue = event.getValue();this.currentState = transitionTable[stateValue][eventValue];this.score += actionTable[stateValue][eventValue];}
}//测试用例
public class AppStart {public static void main(String[] args) {MarioStateMachine marioStateMachine = new MarioStateMachine();marioStateMachine.obtainMushRoom();System.out.println("当前分数:" + marioStateMachine.getScore()+" 当前状态:"+marioStateMachine.getCurrentState());marioStateMachine.obtainCape();System.out.println("当前分数:" + marioStateMachine.getScore()+" 当前状态:"+marioStateMachine.getCurrentState());marioStateMachine.meetMonster();System.out.println("当前分数:" + marioStateMachine.getScore()+" 当前状态:"+marioStateMachine.getCurrentState());}
}
5.5.3 状态模式
//枚举类
public enum State {SMALL(0),SUPER(1),FIRE(2),CAPE(3);private int value;State(int value) {this.value = value;}public int getValue() {return this.value;}
}//状态模式 公共接口
public interface IMario {State getName();void obtainMushRoom(MarioStateMachine machine);void obtainCape(MarioStateMachine machine);void obtainFire(MarioStateMachine machine);void meetMonster(MarioStateMachine machine);
}// 状态机
public class MarioStateMachine {private int score;private IMario mario;public MarioStateMachine() {this.score = 100;this.mario = SmallMario.getInstance();}public void obtainMushRoom(){mario.obtainMushRoom(this);}public void obtainCape(){mario.obtainCape(this);}public void obtainFire(){mario.obtainFire(this);}public void meetMonster(){mario.meetMonster(this);}public int getScore() {return score;}public void setScore(int score) {this.score = score;}public IMario getMario() {return mario;}public void setMario(IMario mario) {this.mario = mario;}
}//超级马里奥
public class SuperMario implements IMario{private static final SuperMario instance = new SuperMario();private SuperMario(){}public static SuperMario getInstance(){return instance;}@Overridepublic State getName() {return State.SUPER;}@Overridepublic void obtainMushRoom(MarioStateMachine machine) {machine.setMario(SuperMario.getInstance());machine.setScore(machine.getScore() + 100);}@Overridepublic void obtainCape(MarioStateMachine machine) {machine.setMario(CapeMario.getInstance());machine.setScore(machine.getScore() + 200);}@Overridepublic void obtainFire(MarioStateMachine machine) {machine.setMario(FireMario.getInstance());machine.setScore(machine.getScore() + 300);}@Overridepublic void meetMonster(MarioStateMachine machine) {machine.setMario(SmallMario.getInstance());machine.setScore(machine.getScore() - 100);}
}//小马里奥
public class SmallMario implements IMario{private static final SmallMario instance = new SmallMario();private SmallMario(){}public static SmallMario getInstance(){return instance;}@Overridepublic State getName() {return State.SMALL;}@Overridepublic void obtainMushRoom(MarioStateMachine machine) {}@Overridepublic void obtainCape(MarioStateMachine machine) {machine.setMario(CapeMario.getInstance());machine.setScore(machine.getScore() + 200);}@Overridepublic void obtainFire(MarioStateMachine machine) {machine.setMario(SmallMario.getInstance());machine.setScore(machine.getScore() + 300);}@Overridepublic void meetMonster(MarioStateMachine machine) {}
}//火焰马里奥
public class FireMario implements IMario{private static final FireMario instance = new FireMario();private FireMario(){}public static FireMario getInstance(){return instance;}@Overridepublic State getName() {return State.FIRE;}@Overridepublic void obtainMushRoom(MarioStateMachine machine) {}@Overridepublic void obtainCape(MarioStateMachine machine) {machine.setMario(CapeMario.getInstance());machine.setScore(machine.getScore() + 200);}@Overridepublic void obtainFire(MarioStateMachine machine) {machine.setMario(FireMario.getInstance());machine.setScore(machine.getScore() + 300);}@Overridepublic void meetMonster(MarioStateMachine machine) {machine.setMario(SmallMario.getInstance());machine.setScore(machine.getScore() - 300);}
}// 帽子马里奥
public class CapeMario implements IMario{private static final CapeMario instance = new CapeMario();private CapeMario(){}public static CapeMario getInstance(){return instance;}@Overridepublic State getName() {return State.CAPE;}@Overridepublic void obtainMushRoom(MarioStateMachine machine) {}@Overridepublic void obtainCape(MarioStateMachine machine) {}@Overridepublic void obtainFire(MarioStateMachine machine) {}@Overridepublic void meetMonster(MarioStateMachine machine) {machine.setMario(SmallMario.getInstance());machine.setScore(machine.getScore() - 200);}
}//测试用例
public class AppStart {public static void main(String[] args) {MarioStateMachine marioStateMachine = new MarioStateMachine();marioStateMachine.obtainMushRoom();System.out.println("当前分数:" + marioStateMachine.getScore()+" 当前状态:"+marioStateMachine.getMario().getName());marioStateMachine.obtainCape();System.out.println("当前分数:" + marioStateMachine.getScore()+" 当前状态:"+marioStateMachine.getMario().getName());marioStateMachine.meetMonster();System.out.println("当前分数:" + marioStateMachine.getScore()+" 当前状态:"+marioStateMachine.getMario().getName());}
}
当前分数:100 当前状态:SMALL
当前分数:300 当前状态:CAPE
当前分数:100 当前状态:SMALL
六 迭代器模式
- 场景:访问聚合对象中的各种元素的时候,如链表的遍历,一般都是将遍历的方法放到链表类中。但如果需要修改遍历方法,就需要修改链表类的代码,违背开闭原则。迭代器模式就是在客户访问和聚合类之间插入一个迭代器,将聚合对象和遍历方法解耦,并且对外隐藏其实现细节。
- 迭代器模式(Iterator Pattern)是行为型设计模式之一,用于提供一种统一的方式来访问集合中的元素,同时隐藏集合的内部结构。
6.1 迭代器模式的核心角色
- Iterator(迭代器接口):定义遍历集合的基本操作,如
hasNext()
、next()
等。 - ConcreteIterator(具体迭代器):实现迭代器接口,并跟踪遍历过程中的当前位置。
- Aggregate(集合接口):定义创建相应迭代器对象的方法,如
iterator()
。 - ConcreteAggregate(具体集合):实现创建具体迭代器对象的方法,返回一个与该集合相关的迭代器。
6.2 迭代器模式的实现代码
// 迭代器接口
interface Iterator<T> {boolean hasNext();T next();
}// 具体迭代器
class ListIterator<T> implements Iterator<T> {private List<T> items;private int position = 0;public ListIterator(List<T> items) {this.items = items;}@Overridepublic boolean hasNext() {return position < items.size();}@Overridepublic T next() {if (hasNext()) {return items.get(position++);}return null;}
}// 集合接口
interface Aggregate<T> {Iterator<T> iterator();
}// 具体集合
class ListAggregate<T> implements Aggregate<T> {private List<T> items = new ArrayList<>();public void add(T item) {items.add(item);}@Overridepublic Iterator<T> iterator() {return new ListIterator<>(items);}
}
- 测试用例
public class Main {public static void main(String[] args) {ListAggregate<String> aggregate = new ListAggregate<>();aggregate.add("A");aggregate.add("B");aggregate.add("C");Iterator<String> iterator = aggregate.iterator();while (iterator.hasNext()) {System.out.print(iterator.next()); # A B C}}
}
6.3 迭代器模式的优点
- 解耦:分离集合对象的使用和内部结构的遍历逻辑。
- 扩展性强:可以为不同集合类型定义不同的迭代器。
- 统一接口:客户端无需知道集合的具体类型即可遍历元素。
6.4 迭代器模式的适用场景
- 当需要统一访问多种集合类型时。
- 需要隐藏集合内部结构时。
- 支持多种遍历方式(如倒序、过滤等)。
6.5 迭代器模式的Java 内置支持
Java 标准库已内置迭代器模式:
java.util.Iterator
是标准的迭代器接口。java.lang.Iterable
接口定义了iterator()
方法,许多集合类(如List
、Set
)都实现了它。
// 增强型 for 循环底层就依赖于 `Iterable` 和 `Iterator`。
List<String> list = Arrays.asList("X", "Y", "Z");
for (String s : list) {System.out.println(s);
}
七 访问者模式
- 访问者模式(Visitor Pattern)是一种行为型设计模式,它允许你将作用于某些对象结构中的各元素的操作分离出来,集中到一个访问者对象中,从而使得不改变对象结构的情况下增加新的操作。【解耦数据结构和操作】
- 访问者模式适用于对象结构稳定、操作多变的场景,通过将操作从对象结构中抽离,实现了高内聚低耦合的设计理念。但在实际使用中需权衡是否值得牺牲封装性来换取灵活性。
7.1 访问者模式的核心思想
- 将数据结构与数据操作分离。
- 在不修改元素类的前提下,为元素添加新的操作。
7.2 访问者模式的核心角色
角色 | 描述 |
---|---|
Visitor | 抽象访问者接口,定义对各个元素的访问操作。 |
ConcreteVisitor | 具体访问者实现,实现针对不同元素的具体操作。 |
Element | 抽象元素接口,定义接受访问者的方法 accept(Visitor visitor) 。 |
ConcreteElement | 具体元素实现,实现 accept 方法,并调用访问者的处理方法。 |
ObjectStructure | 对象结构,包含一组元素对象,提供让访问者访问的接口。 |
7.3 访问者模式的代码实现
// Visitor 接口
interface Visitor {void visit(ConcreteElementA elementA);void visit(ConcreteElementB elementB);
}// 具体访问者
class ConcreteVisitor implements Visitor {@Overridepublic void visit(ConcreteElementA elementA) {System.out.println("访问者处理元素 A:" + elementA.operation());}@Overridepublic void visit(ConcreteElementB elementB) {System.out.println("访问者处理元素 B:" + elementB.operation());}
}// Element 接口
interface Element {void accept(Visitor visitor);
}// 具体元素 A
class ConcreteElementA implements Element {@Overridepublic void accept(Visitor visitor) {visitor.visit(this);}public String operation() {return "元素 A 的操作";}
}// 具体元素 B
class ConcreteElementB implements Element {@Overridepublic void accept(Visitor visitor) {visitor.visit(this);}public String operation() {return "元素 B 的操作";}
}// 对象结构
class ObjectStructure {private List<Element> elements = new ArrayList<>();public void add(Element element) {elements.add(element);}public void accept(Visitor visitor) {for (Element element : elements) {element.accept(visitor);}}
}// 测试类
public class TestVisitorPattern {public static void main(String[] args) {ObjectStructure structure = new ObjectStructure();structure.add(new ConcreteElementA());structure.add(new ConcreteElementB());Visitor visitor = new ConcreteVisitor();structure.accept(visitor);}
}
7.4 访问者模式的使用场景
- 对象结构稳定,但需要经常定义新的操作。
- 需要对多个不相关的类执行某些公共逻辑,又不想在每个类中都实现该逻辑。
- 操作依赖对象的状态,但不希望这些操作污染类本身。
7.5 访问者模式的优缺点
优点 | 缺点 |
---|---|
增加新的访问操作容易,符合开闭原则。 | 如果对象结构频繁变化(如新增元素类型),则维护困难。 |
操作集中管理,便于扩展和维护。 | 具体元素必须暴露自身细节给访问者,破坏封装性。 |
八 备忘录模式
- 备忘录模式(Memento Pattern)是行为型设计模式之一,用于在不破坏对象封装性的前提下,捕获并保存对象的内部状态,以便以后可以恢复到该状态。
- 备忘录模式通过将对象的状态存储为备忘录对象,实现了对象状态的保存与恢复。它广泛应用于需要撤销/重做功能的场景,例如文本编辑器、游戏存档等。虽然备忘录模式具有良好的封装性,但也需要注意内存占用问题。
8.1 备忘录模式的核心思想
- 保存对象的状态:将对象的状态保存为一个备忘录对象。
- 恢复对象的状态:通过备忘录对象还原对象的内部状态。
- 不暴露对象的内部细节:通过封装机制,避免直接访问对象的私有数据。
8.2 备忘录模式的核心角色
备忘录模式包含以下三个主要角色:
角色 | 职责 |
---|---|
Originator (发起人) | 创建一个备忘录来记录当前对象的状态,并可以从备忘录中恢复状态。 |
Memento (备忘录) | 存储发起人的状态,通常是一个不可变对象。 |
Caretaker (管理者) | 负责保存和提供备忘录,但不能修改备忘录的内容。 |
8.3 备忘录模式的代码实现
- 简单的 Java 实现示例
// Memento: 备忘录类
class Memento {private String state;public Memento(String state) {this.state = state;}public String getState() {return state;}
}// Originator: 发起人类
class Originator {private String state;public void setState(String state) {this.state = state;}public String getState() {return state;}// 创建备忘录public Memento saveStateToMemento() {return new Memento(state);}// 恢复状态public void restoreStateFromMemento(Memento memento) {state = memento.getState();}
}// Caretaker: 管理者类
class Caretaker {private List<Memento> mementoList = new ArrayList<>();public void add(Memento memento) {mementoList.add(memento);}public Memento get(int index) {return mementoList.get(index);}
}
- 测试用例
public class MementoPatternDemo {public static void main(String[] args) {Originator originator = new Originator();Caretaker caretaker = new Caretaker();originator.setState("State #1");caretaker.add(originator.saveStateToMemento());originator.setState("State #2");caretaker.add(originator.saveStateToMemento());originator.setState("State #3");System.out.println("Current State: " + originator.getState());// 恢复到之前的状态originator.restoreStateFromMemento(caretaker.get(0));System.out.println("First saved State: " + originator.getState());originator.restoreStateFromMemento(caretaker.get(1));System.out.println("Second saved State: " + originator.getState());}
}
Current State: State #3
First saved State: State #1
Second saved State: State #2
8.4 备忘录模式的优缺点
优点 | 缺点 |
---|---|
封装性好:不暴露对象的内部细节。 | 可能占用较多内存,特别是保存大量状态时。 |
支持状态回滚:方便实现撤销/重做功能。 | 如果状态频繁变化,管理备忘录可能变得复杂。 |
8.5 备忘录模式的应用场景
备忘录模式适用于以下场景:
- 需要保存对象的历史状态,以便后续恢复。
- 需要实现撤销/重做功能。
- 不希望暴露对象的内部状态,同时需要保存其状态。
九命令模式
-
命令模式(Command Pattern)是行为型设计模式之一,用于将请求封装为对象,从而实现请求的队列化、日志记录、撤销/重做操作等功能。以下是关键点:
-
命令模式将一个请求封装成一个对象,从而使用户能够用不同的请求对客户端进行参数化。
9.1 命令模式的核心角色
Command
接口:定义执行操作的公共方法(如execute()
)。ConcreteCommand
类:具体命令类,持有对接收者对象的引用,并实现在Command
接口中定义的方法。Receiver
接口:定义实际执行操作的对象接口。Invoker
类:持有命令对象,并调用其execute()
方法来触发请求。Client
类:负责创建具体的命令对象并绑定到Invoker
上。
9.2 命令模式的代码实现
// 定义命令接口
public interface Command {void execute();
}// 具体命令类
public class LightOnCommand implements Command {private Light light;public LightOnCommand(Light light) {this.light = light;}@Overridepublic void execute() {light.on();}
}// 接收者类
public class Light {public void on() {System.out.println("Light is on");}public void off() {System.out.println("Light is off");}
}// 调用者类
public class RemoteControl {private Command command;public void setCommand(Command command) {this.command = command;}public void pressButton() {command.execute();}
}// 客户端使用
public class Client {public static void main(String[] args) {Light light = new Light();Command lightOn = new LightOnCommand(light);RemoteControl remote = new RemoteControl();remote.setCommand(lightOn);remote.pressButton(); // 输出 "Light is on"}
}
9.3 命令模式的优点
- 解耦:请求发送者和接收者相互独立,只需通过命令对象沟通。
- 扩展性强:可以轻松新增新的命令类型而无需修改已有代码。
- 支持撤销/重做:通过记录命令历史,可以方便地实现这些功能。
9.4 命令模式的适用场景
- 需要支持事务回滚或日志记录的操作。
- 系统需要解耦请求的发送者与执行者。
- 提供命令队列处理,例如任务调度系统。
十 解释器模式
- 解释器模式(Interpreter Pattern)是行为型设计模式之一,它用于定义语言的文法,并解析执行该语言的句子或表达式。给定一个语言,定义它的文法的一种表示,并定义一个解释器,使用该解释器来解释语言中的句子。
- 解释器模式适合处理小型、结构固定的文法,但在实际开发中由于其维护成本较高,通常结合其他方式(如脚本引擎、ANTLR 等工具)实现更复杂的语言解析。
10.1 解释器模式的核心角色
- 抽象表达式(Expression):定义解释操作的公共接口。
- 终结符表达式(Terminal Expression):实现与文法中终结符相关的解释操作。
- 非终结符表达式(Non-terminal Expression):对应文法中非终结符,通常包含多个子表达式,递归组合解释。
- 上下文环境(Context):包含解释器需要的全局信息,例如变量值、状态等。
- 客户端(Client):构建语法树并调用解释方法。
10.2 解释器模式的代码实现
- 一个简单的数学表达式解释器示例,支持加法和减法:
// 抽象表达式
interface Expression {int interpret(Context context);
}// 终结符表达式:数字
class NumberExpression implements Expression {private int number;public NumberExpression(int number) {this.number = number;}@Overridepublic int interpret(Context context) {return number;}
}// 终结符表达式:变量
class VariableExpression implements Expression {private String name;public VariableExpression(String name) {this.name = name;}@Overridepublic int interpret(Context context) {return context.getVariable(name);}
}// 非终结符表达式:加法
class AddExpression implements Expression {private Expression left, right;public AddExpression(Expression left, Expression right) {this.left = left;this.right = right;}@Overridepublic int interpret(Context context) {return left.interpret(context) + right.interpret(context);}
}// 非终结符表达式:减法
class SubtractExpression implements Expression {private Expression left, right;public SubtractExpression(Expression left, Expression right) {this.left = left;this.right = right;}@Overridepublic int interpret(Context context) {return left.interpret(context) - right.interpret(context);}
}// 上下文环境
class Context {private Map<String, Integer> variables = new HashMap<>();// 设置变量值public void setVariable(String name, int value) {variables.put(name, value);}// 获取变量值public int getVariable(String name) {Integer value = variables.get(name);if (value == null) {throw new IllegalArgumentException("变量 " + name + " 未定义");}return value;}
}// 客户端使用
public class Client {public static void main(String[] args) {// 构建表达式:x + y - 3Expression expr = new SubtractExpression(new AddExpression(new VariableExpression("x"), new VariableExpression("y")),new NumberExpression(3));Context context = new Context();context.setVariable("x", 10);context.setVariable("y", 5);int result = expr.interpret(context);System.out.println("结果: " + result); // 输出 12}
}
10.3 解释器模式的优缺点
优点 | 缺点 |
---|---|
易于扩展文法规则,符合开闭原则 | 类的数量多,系统复杂度高 |
实现了文法规则与解释的分离 | 对于复杂语法效率低 |
10.4 解释器模式的适用场景
- 需要构建一种小型语言或DSL(领域特定语言),如规则引擎、数学表达式计算等。
- 文法简单且性能要求不高时。
- 当语法规则的变化频率较低时。
10.5 解释器模式的实际应用
- 正则表达式解析
- SQL 解析
- XML/JSON 解析器
- 规则引擎(如配置规则表达式)
十一 中介模式
- 中介者模式(Mediator Pattern)是行为型设计模式之一,用于降低多个对象之间的直接耦合。它通过引入一个中介者对象来封装一系列对象的交互逻辑,使得各个对象不需要显式地相互引用,从而实现松耦合。
11.1 中介者模式的核心角色
- Mediator:中介者接口,定义了同事对象之间通信的方法。
- ConcreteMediator:具体中介者类,实现了Mediator接口,并协调各个同事对象之间的交互。
- Colleague:同事类接口或抽象类,通常包含一个对Mediator的引用,并通过Mediator进行通信。
- ConcreteColleague:具体的同事类,实现自己的业务逻辑,并通过Mediator与其他同事进行交互。
11.2 终结者模式的代码实现
// Mediator 接口
public interface Mediator {void send(String message, Colleague colleague);
}// ConcreteMediator 类
public class ConcreteMediator implements Mediator {private ColleagueA colleagueA;private ColleagueB colleagueB;public void setColleagueA(ColleagueA colleagueA) {this.colleagueA = colleagueA;}public void setColleagueB(ColleagueB colleagueB) {this.colleagueB = colleagueB;}@Overridepublic void send(String message, Colleague colleague) {if (colleague == colleagueA) {colleagueB.receive(message);} else if (colleague == colleagueB) {colleagueA.receive(message);}}
}// Colleague 抽象类
public abstract class Colleague {protected Mediator mediator;public Colleague(Mediator mediator) {this.mediator = mediator;}public abstract void send(String message);public abstract void receive(String message);
}// ConcreteColleagueA 类
public class ColleagueA extends Colleague {public ColleagueA(Mediator mediator) {super(mediator);}@Overridepublic void send(String message) {mediator.send(message, this);}@Overridepublic void receive(String message) {System.out.println("ColleagueA received: " + message);}
}// ConcreteColleagueB 类
public class ColleagueB extends Colleague {public ColleagueB(Mediator mediator) {super(mediator);}@Overridepublic void send(String message) {mediator.send(message, this);}@Overridepublic void receive(String message) {System.out.println("ColleagueB received: " + message);}
}// 使用示例
public class Client {public static void main(String[] args) {ConcreteMediator mediator = new ConcreteMediator();ColleagueA colleagueA = new ColleagueA(mediator);ColleagueB colleagueB = new ColleagueB(mediator);mediator.setColleagueA(colleagueA);mediator.setColleagueB(colleagueB);colleagueA.send("Hello from ColleagueA");colleagueB.send("Hi from ColleagueB");}
}
11.3 中介者模式的应用场景
- 当多个对象之间存在复杂的交互逻辑时,使用中介者模式可以简化这些对象之间的关系。
- 在需要解耦系统中的组件时,例如GUI组件之间的通信、系统模块间的协调等。
- 中介者模式适用于需要集中控制交互逻辑的场景,避免对象之间直接依赖。
11.4 中介者模式的优缺点
优点
- 降低耦合度:对象之间不再直接通信,而是通过中介者进行交互,减少了对象之间的依赖关系。
- 提高可维护性:将交互逻辑集中在一个中介者中,便于维护和扩展。
- 增强可复用性:同事对象可以独立变化,不会影响其他对象。
缺点 - 中介者复杂度增加:随着系统的复杂度增加,中介者的逻辑可能会变得非常复杂,难以维护。
- 性能问题:由于所有交互都必须通过中介者,可能会影响系统的性能。
11.5 中介者模式的适用性
- 当对象之间的交互复杂且难以管理时。
- 当希望减少对象之间的直接依赖时。
- 当需要集中管理多个对象之间的交互逻辑时。