行为型设计模式是一类设计模式,它们关注的是对象之间的相互作用,以及对象如何通过消息传递来实现松耦合。这些模式涉及到算法和对象之间职责的分配。在本文中,我们将深入探讨几种常见的行为型模式,并提供详细的解释、示例和应用场景。
1. 责任链模式 (Chain of Responsibility Pattern)
责任链模式旨在解耦发送者和接收者,通过构建一条责任链来逐一处理请求。其核心思想是请求沿着链传递,直到有一个处理者能够处理它为止。
概念和作用
责任链模式的主要目的是避免将请求的发送者与接收者耦合在一起,从而使得请求的发送者无需知道请求的具体处理者。这种解耦使得系统更灵活,更易于扩展。
结构和角色
责任链模式由三个主要角色组成:抽象处理者、具体处理者和客户端。
- 抽象处理者(Handler):定义了处理请求的接口,并维护一个指向下一个处理者的引用。
- 具体处理者(ConcreteHandler):实现了处理请求的方法,并在必要时将请求传递给下一个处理者。
- 客户端(Client):创建责任链,并将请求发送到链中的第一个处理者。
应用场景和实例
责任链模式常用于日志记录、权限验证等场景。例如,一个请求可能需要经过多个层级的权限验证,每个层级都有不同的处理逻辑,责任链模式可以很好地应用于这种情况。
// 定义抽象处理者
public abstract class Handler {
protected Handler nextHandler;
public void setNextHandler(Handler handler) {
this.nextHandler = handler;
}
public abstract void handleRequest(Request request);
}
// 具体处理者
public class ConcreteHandler extends Handler {
public void handleRequest(Request request) {
if (canHandle(request)) {
// 处理请求的逻辑
} else if (nextHandler != null) {
nextHandler.handleRequest(request);
}
}
private boolean canHandle(Request request) {
// 判断是否能处理该请求的逻辑
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Handler handler1 = new ConcreteHandler();
Handler handler2 = new ConcreteHandler();
handler1.setNextHandler(handler2);
handler1.handleRequest(request);
}
}
在上面的示例中,如果第一个处理者无法处理请求,它会将请求传递给下一个处理者,直到有一个处理者能够处理为止。
责任链模式的灵活性使得它在许多场景下都能发挥作用,我们可以根据具体的需求来设计和组织责任链,从而实现更好的代码复用和可维护性。
2. 命令模式 (Command Pattern)
命令模式旨在将请求封装成对象,从而使得可以参数化客户端对象、队列或记录请求日志,并支持可撤销的操作。
概念和作用
命令模式的核心思想是将请求封装成对象,从而使得请求的发送者和接收者之间解耦。这样,发送者无需知道请求的具体接收者,而是将请求发送给一个命令对象,由命令对象负责调用接收者的方法。
通过将请求封装成对象,我们可以实现以下几个目标:
- 参数化对象:命令对象可以在运行时被参数化,使得我们可以动态地传递参数给命令对象。
- 支持队列和日志:我们可以将命令对象存储在队列中,以便后续执行;或者记录命令对象的执行日志,以便撤销操作。
- 支持撤销:命令对象可以包含撤销操作的逻辑,从而支持撤销上一步操作。
结构和角色
命令模式由四个主要角色组成:命令接口、具体命令、调用者和接收者。
- 命令接口(Command):定义了执行命令的方法。
- 具体命令(ConcreteCommand):实现了命令接口,持有一个接收者对象,并在执行时调用接收者的方法。
- 调用者(Invoker):负责调用命令对象执行请求。
- 接收者(Receiver):实际执行命令的对象。
应用场景和实例
命令模式常用于菜单命令、遥控器等场景。例如,一个遥控器可以包含多个按钮,每个按钮对应一个命令,当用户按下按钮时,遥控器会调用相应命令的执行方法。
// 定义命令接口
public interface Command {
void execute();
}
// 具体命令
public class ConcreteCommand implements Command {
private Receiver receiver;
public ConcreteCommand(Receiver receiver) {
this.receiver = receiver;
}
public void execute() {
receiver.action();
}
}
// 调用者
public class Invoker {
private Command command;
public void setCommand(Command command) {
this.command = command;
}
public void executeCommand() {
command.execute();
}
}
// 接收者
public class Receiver {
public void action() {
// 执行具体操作的逻辑
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Receiver receiver = new Receiver();
Command command = new ConcreteCommand(receiver);
Invoker invoker = new Invoker();
invoker.setCommand(command);
invoker.executeCommand();
}
}
在上面的示例中,我们创建了一个具体命令对象,并将其关联到一个接收者对象。然后,我们创建了一个调用者对象,并将具体命令对象设置到调用者中。最后,调用者执行命令,从而触发接收者执行具体操作。
命令模式的使用使得请求发送者和接收者之间解耦,从而提高了系统的灵活性和可扩展性。同时,命令模式也可以支持撤销和重做操作,使得系统更加健壮和易用。
3. 解释器模式 (Interpreter Pattern)
解释器模式旨在定义语言的文法,并建立一个解释器来解释语言中的句子。它通常用于处理特定领域的语言或语法。
概念和作用
解释器模式的核心思想是将一个语言的文法表示为一个解释器,然后使用该解释器来解释句子。它通常用于处理特定领域的语言或语法,例如正则表达式、SQL解析等。
结构和角色
解释器模式由三个主要角色组成:抽象表达式、终结符表达式和非终结符表达式。
- 抽象表达式(AbstractExpression):定义了解释器的接口,声明了解释操作的方法。
- 终结符表达式(TerminalExpression):实现了解释器的接口,表示文法中的终结符。
- 非终结符表达式(NonterminalExpression):实现了解释器的接口,表示文法中的非终结符,它通常由多个终结符和/或非终结符组成。
应用场景和实例
解释器模式常用于处理特定领域的语言或语法。例如,我们可以使用解释器模式来解析和执行正则表达式、SQL语句等。
// 抽象表达式
public interface Expression {
boolean interpret(String context);
}
// 终结符表达式
public class TerminalExpression implements Expression {
private String data;
public TerminalExpression(String data) {
this.data = data;
}
public boolean interpret(String context) {
return context.contains(data);
}
}
// 非终结符表达式
public class OrExpression implements Expression {
private Expression expr1;
private Expression expr2;
public OrExpression(Expression expr1, Expression expr2) {
this.expr1 = expr1;
this.expr2 = expr2;
}
public boolean interpret(String context) {
return expr1.interpret(context) || expr2.interpret(context);
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Expression expr1 = new TerminalExpression("hello");
Expression expr2 = new TerminalExpression("world");
Expression orExpr = new OrExpression(expr1, expr2);
System.out.println(orExpr.interpret("hello")); // true
System.out.println(orExpr.interpret("world")); // true
System.out.println(orExpr.interpret("foo")); // false
}
}
在上面的示例中,我们定义了一个简单的解释器来解释包含“hello”或“world”的句子。通过使用解释器模式,我们可以轻松地扩展和修改语法规则,而不必修改解释器的代码。
解释器模式适用于需要处理特定领域语言或语法的场景,它提供了一种灵活且可扩展的解决方案。
4. 迭代器模式 (Iterator Pattern)
迭代器模式旨在提供一种顺序访问聚合对象中的各个元素,而又不暴露其内部表示。它可以让我们在不知道聚合对象内部结构的情况下,顺序地访问聚合对象中的元素。
概念和作用
迭代器模式的核心思想是将对集合元素的遍历与集合本身分离,使得我们可以使用统一的接口来访问集合中的元素,而不用关心底层的数据结构。
结构和角色
迭代器模式由两个主要角色组成:迭代器接口和聚合对象。
- 迭代器接口(Iterator):定义了访问和遍历聚合对象中元素的方法。
- 具体迭代器(ConcreteIterator):实现了迭代器接口,负责实现对聚合对象的遍历。
- 聚合对象(Aggregate):定义了创建相应迭代器的接口。
- 具体聚合对象(ConcreteAggregate):实现了聚合对象接口,负责创建相应的迭代器。
应用场景和实例
迭代器模式常用于需要遍历集合对象的场景,例如集合类的迭代器、文件系统的迭代器等。
// 迭代器接口
public interface Iterator<T> {
boolean hasNext();
T next();
}
// 聚合对象接口
public interface Aggregate<T> {
Iterator<T> createIterator();
}
// 具体迭代器
public class ConcreteIterator<T> implements Iterator<T> {
private List<T> list;
private int position = 0;
public ConcreteIterator(List<T> list) {
this.list = list;
}
public boolean hasNext() {
return position < list.size();
}
public T next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
return list.get(position++);
}
}
// 具体聚合对象
public class ConcreteAggregate<T> implements Aggregate<T> {
private List<T> list;
public ConcreteAggregate(List<T> list) {
this.list = list;
}
public Iterator<T> createIterator() {
return new ConcreteIterator<>(list);
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
List<Integer> data = Arrays.asList(1, 2, 3, 4, 5);
Aggregate<Integer> aggregate = new ConcreteAggregate<>(data);
Iterator<Integer> iterator = aggregate.createIterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
在上面的示例中,我们定义了一个简单的迭代器来遍历整数列表。通过使用迭代器模式,我们可以将聚合对象与遍历方式解耦,从而提高了代码的灵活性和可维护性。
迭代器模式适用于需要遍历集合对象的场景,它提供了一种统一的接口来访问聚合对象中的元素,而不用关心底层的数据结构。
5. 中介者模式 (Mediator Pattern)
中介者模式旨在用一个中介对象来封装一系列对象的交互,使得对象之间不直接相互引用,从而降低耦合。它可以减少对象之间的直接通信,而是通过中介者来进行间接通信。
概念和作用
中介者模式的核心思想是将对象之间的交互行为集中在一个中介者对象中,而不是分散在各个对象之间。通过这种方式,可以减少对象之间的直接依赖关系,降低耦合度,提高系统的灵活性和可维护性。
结构和角色
中介者模式由三个主要角色组成:抽象中介者、具体中介者和同事类。
- 抽象中介者(Mediator):定义了同事对象之间交互的接口。
- 具体中介者(ConcreteMediator):实现了中介者接口,负责协调各个同事对象之间的交互。
- 同事类(Colleague):每个同事对象都知道中介者对象,并通过中介者来进行间接通信。
应用场景和实例
中介者模式常用于需要多个对象之间相互交互的场景,例如聊天室、飞机调度系统等。
// 抽象中介者
public interface Mediator {
void sendMessage(String message, Colleague colleague);
}
// 具体中介者
public class ConcreteMediator implements Mediator {
private Colleague colleague1;
private Colleague colleague2;
public void setColleague1(Colleague colleague) {
this.colleague1 = colleague;
}
public void setColleague2(Colleague colleague) {
this.colleague2 = colleague;
}
public void sendMessage(String message, Colleague colleague) {
if (colleague == colleague1) {
colleague2.receiveMessage(message);
} else if (colleague == colleague2) {
colleague1.receiveMessage(message);
}
}
}
// 同事类
public abstract class Colleague {
protected Mediator mediator;
public Colleague(Mediator mediator) {
this.mediator = mediator;
}
public abstract void sendMessage(String message);
public abstract void receiveMessage(String message);
}
public class ConcreteColleague1 extends Colleague {
public ConcreteColleague1(Mediator mediator) {
super(mediator);
}
public void sendMessage(String message) {
mediator.sendMessage(message, this);
}
public void receiveMessage(String message) {
System.out.println("ConcreteColleague1 received message: " + message);
}
}
public class ConcreteColleague2 extends Colleague {
public ConcreteColleague2(Mediator mediator) {
super(mediator);
}
public void sendMessage(String message) {
mediator.sendMessage(message, this);
}
public void receiveMessage(String message) {
System.out.println("ConcreteColleague2 received message: " + message);
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
ConcreteMediator mediator = new ConcreteMediator();
Colleague colleague1 = new ConcreteColleague1(mediator);
Colleague colleague2 = new ConcreteColleague2(mediator);
mediator.setColleague1(colleague1);
mediator.setColleague2(colleague2);
colleague1.sendMessage("Hello from Colleague1!");
colleague2.sendMessage("Hi from Colleague2!");
}
}
在上面的示例中,我们创建了一个简单的聊天室系统,其中包含两个同事对象(ConcreteColleague1和ConcreteColleague2)和一个中介者对象(ConcreteMediator)。通过中介者模式,我们实现了两个同事对象之间的间接通信,从而降低了它们之间的耦合度。
中介者模式适用于多个对象之间需要相互交互的场景,它可以减少对象之间的直接依赖关系,提高系统的灵活性和可维护性。
6. 备忘录模式 (Memento Pattern)
备忘录模式旨在在不破坏封装性的前提下,捕获对象的内部状态,并在对象之外保存这个状态,以便之后恢复对象。它允许我们将对象的状态保存到备忘录中,并在需要时将其恢复。
概念和作用
备忘录模式的核心思想是在不破坏对象封装性的情况下,将对象的状态保存到备忘录中,并在需要时将其恢复。它可以用于实现撤销机制、编辑器恢复功能等。
结构和角色
备忘录模式由三个主要角色组成:备忘录、发起人和负责人。
- 备忘录(Memento):负责存储发起人对象的内部状态。
- 发起人(Originator):负责创建备忘录对象,并将自己的状态保存到备忘录中。
- 负责人(Caretaker):负责保存备忘录对象,并在需要时将其提供给发起人。
应用场景和实例
备忘录模式常用于需要保存和恢复对象状态的场景,例如撤销机制、编辑器恢复功能等。
// 备忘录
public class Memento {
private String state;
public Memento(String state) {
this.state = state;
}
public String getState() {
return state;
}
}
// 发起人
public class Originator {
private String state;
public void setState(String state) {
this.state = state;
}
public String getState() {
return state;
}
public Memento createMemento() {
return new Memento(state);
}
public void restoreMemento(Memento memento) {
this.state = memento.getState();
}
}
// 负责人
public class Caretaker {
private Memento memento;
public void saveMemento(Memento memento) {
this.memento = memento;
}
public Memento retrieveMemento() {
return memento;
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Originator originator = new Originator();
Caretaker caretaker = new Caretaker();
// 改变发起人状态并保存备忘录
originator.setState("State1");
caretaker.saveMemento(originator.createMemento());
// 再次改变发起人状态
originator.setState("State2");
// 恢复到之前的状态
originator.restoreMemento(caretaker.retrieveMemento());
System.out.println("Current state: " + originator.getState()); // 输出 "Current state: State1"
}
}
在上面的示例中,我们使用备忘录模式实现了一个简单的撤销机制。通过将发起人对象的状态保存到备忘录中,并在需要时进行恢复,我们可以实现撤销操作,从而回到之前的状态。
备忘录模式适用于需要保存和恢复对象状态的场景,它提供了一种灵活的方式来实现撤销和恢复功能,而不破坏对象的封装性。
7. 观察者模式 (Observer Pattern)
观察者模式旨在定义对象间一种一对多的依赖关系,当一个对象的状态发生改变时,其所有依赖者都会收到通知并自动更新。它允许对象之间保持松耦合关系,从而提高系统的灵活性和可维护性。
概念和作用
观察者模式的核心思想是定义一个一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会收到通知并自动更新。它可以用于实现事件监听、消息订阅等。
结构和角色
观察者模式由四个主要角色组成:抽象主题、具体主题、抽象观察者和具体观察者。
- 抽象主题(Subject):定义了具体主题和观察者之间的接口,提供了添加、删除和通知观察者的方法。
- 具体主题(ConcreteSubject):实现了抽象主题接口,负责维护具体观察者的列表,并在状态发生改变时通知观察者。
- 抽象观察者(Observer):定义了接收通知的方法。
- 具体观察者(ConcreteObserver):实现了抽象观察者接口,负责接收具体主题的通知并进行相应的处理。
应用场景和实例
观察者模式常用于需要实现一对多的依赖关系的场景,例如消息订阅、GUI界面更新等。
// 抽象主题
public interface Subject {
void attach(Observer observer);
void detach(Observer observer);
void notifyObservers();
}
// 具体主题
public class ConcreteSubject implements Subject {
private List<Observer> observers = new ArrayList<>();
private int state;
public void setState(int state) {
this.state = state;
notifyObservers();
}
public int getState() {
return state;
}
public void attach(Observer observer) {
observers.add(observer);
}
public void detach(Observer observer) {
observers.remove(observer);
}
public void notifyObservers() {
for (Observer observer : observers) {
observer.update();
}
}
}
// 抽象观察者
public interface Observer {
void update();
}
// 具体观察者
public class ConcreteObserver implements Observer {
private ConcreteSubject subject;
public ConcreteObserver(ConcreteSubject subject) {
this.subject = subject;
this.subject.attach(this);
}
public void update() {
System.out.println("Observer received notification. New state: " + subject.getState());
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
ConcreteSubject subject = new ConcreteSubject();
ConcreteObserver observer1 = new ConcreteObserver(subject);
ConcreteObserver observer2 = new ConcreteObserver(subject);
subject.setState(1);
subject.setState(2);
}
}
在上面的示例中,我们创建了一个简单的观察者模式实现。具体主题(ConcreteSubject)负责维护观察者列表,并在状态发生改变时通知观察者。具体观察者(ConcreteObserver)实现了观察者接口,负责接收主题的通知并进行相应的处理。
观察者模式适用于需要实现一对多的依赖关系的场景,它可以提高系统的灵活性和可维护性,使得对象之间的关系更加松耦合。
8. 状态模式 (State Pattern)
状态模式旨在允许对象在内部状态改变时改变其行为,使得对象看起来似乎修改了其类。它将状态封装成独立的类,并将状态的变化委托给不同的状态类来处理,从而实现了状态的变化与行为的解耦。
概念和作用
状态模式的核心思想是将对象的行为与其内部状态分离,并将不同状态对应的行为封装到不同的状态类中。当对象的状态发生改变时,它会委托给对应的状态类来处理,从而实现了状态的变化与行为的解耦。
结构和角色
状态模式由三个主要角色组成:环境类、抽象状态类和具体状态类。
- 环境类(Context):维护一个状态对象,并在需要时将状态的变化委托给状态对象来处理。
- 抽象状态类(State):定义了一个接口,用于封装与环境类的一个特定状态相关的行为。
- 具体状态类(ConcreteState):实现了抽象状态类定义的接口,并实现了具体状态对应的行为。
应用场景和实例
状态模式常用于对象具有多个状态,并且状态之间需要相互转换的场景,例如状态机、订单状态转换等。
// 抽象状态类
public interface State {
void handle();
}
// 具体状态类
public class ConcreteStateA implements State {
public void handle() {
System.out.println("Handling state A");
}
}
public class ConcreteStateB implements State {
public void handle() {
System.out.println("Handling state B");
}
}
// 环境类
public class Context {
private State state;
public void setState(State state) {
this.state = state;
}
public void request() {
state.handle();
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Context context = new Context();
State stateA = new ConcreteStateA();
State stateB = new ConcreteStateB();
context.setState(stateA);
context.request();
context.setState(stateB);
context.request();
}
}
在上面的示例中,我们创建了一个简单的状态模式实现。具体状态类(ConcreteStateA和ConcreteStateB)实现了抽象状态类定义的接口,并分别实现了状态A和状态B对应的行为。环境类(Context)维护一个状态对象,并在需要时将状态的变化委托给状态对象来处理。
状态模式适用于对象具有多个状态,并且状态之间需要相互转换的场景,它可以有效地将状态的变化与行为的实现分离,提高了代码的可维护性和灵活性。
9. 策略模式 (Strategy Pattern)
策略模式旨在定义一系列算法,将每个算法封装起来,并使它们可以互相替换,从而使得算法可以独立于使用它的客户端变化。它将算法的实现与使用算法的客户端分离,提高了代码的灵活性和可维护性。
概念和作用
策略模式的核心思想是将算法的实现封装成独立的策略类,并将策略类作为参数传递给使用算法的客户端。这样客户端可以根据需要选择不同的策略,而不用修改原有的代码。
结构和角色
策略模式由三个主要角色组成:策略接口、具体策略类和环境类。
- 策略接口(Strategy):定义了一个算法的接口,用于封装具体的算法实现。
- 具体策略类(ConcreteStrategy):实现了策略接口定义的算法,并负责执行具体的业务逻辑。
- 环境类(Context):维护一个对策略对象的引用,并在需要时调用策略对象的方法来执行算法。
应用场景和实例
策略模式常用于需要在运行时动态选择算法的场景,例如排序算法、支付方式选择等。
// 策略接口
public interface PaymentStrategy {
void pay(double amount);
}
// 具体策略类
public class CreditCardPaymentStrategy implements PaymentStrategy {
private String cardNumber;
private String expiryDate;
private String cvv;
public CreditCardPaymentStrategy(String cardNumber, String expiryDate, String cvv) {
this.cardNumber = cardNumber;
this.expiryDate = expiryDate;
this.cvv = cvv;
}
public void pay(double amount) {
System.out.println("Paying " + amount + " via credit card");
}
}
public class PayPalPaymentStrategy implements PaymentStrategy {
private String email;
private String password;
public PayPalPaymentStrategy(String email, String password) {
this.email = email;
this.password = password;
}
public void pay(double amount) {
System.out.println("Paying " + amount + " via PayPal");
}
}
// 环境类
public class ShoppingCart {
private PaymentStrategy paymentStrategy;
public void setPaymentStrategy(PaymentStrategy paymentStrategy) {
this.paymentStrategy = paymentStrategy;
}
public void checkout(double amount) {
paymentStrategy.pay(amount);
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
ShoppingCart cart = new ShoppingCart();
PaymentStrategy creditCardPayment = new CreditCardPaymentStrategy("1234-5678-9012-3456", "12/25", "123");
PaymentStrategy payPalPayment = new PayPalPaymentStrategy("example@example.com", "password");
cart.setPaymentStrategy(creditCardPayment);
cart.checkout(100.0);
cart.setPaymentStrategy(payPalPayment);
cart.checkout(50.0);
}
}
在上面的示例中,我们创建了一个简单的策略模式实现。具体策略类(CreditCardPaymentStrategy和PayPalPaymentStrategy)实现了策略接口定义的算法,并负责执行具体的支付逻辑。环境类(ShoppingCart)维护一个对策略对象的引用,并在需要时调用策略对象的方法来执行支付操作。
策略模式适用于需要在运行时动态选择算法的场景,它提供了一种灵活的方式来实现算法的替换,而不用修改原有的代码。
10. 模板方法模式 (Template Method Pattern)
模板方法模式旨在定义一个操作中的算法骨架,而将一些步骤延迟到子类中。它通过将算法的不变部分封装到父类中,并将可变部分由子类来实现,从而提高了代码的复用性和扩展性。
概念和作用
模板方法模式的核心思想是定义一个算法的骨架,并将其中的一些步骤延迟到子类中实现。这样可以确保算法的结构不变,同时允许子类根据需要重新实现特定的步骤。
结构和角色
模板方法模式由两个主要角色组成:抽象类和具体类。
- 抽象类(AbstractClass):定义了一个算法的骨架,其中包含了一些抽象方法和具体方法,抽象方法由子类来实现,具体方法由父类来实现。
- 具体类(ConcreteClass):实现了抽象类定义的抽象方法,从而完成算法的具体实现。
应用场景和实例
模板方法模式常用于实现一些具有固定流程的算法,例如编译器的编译过程、游戏中的角色行动等。
// 抽象类
public abstract class Game {
abstract void initialize();
abstract void startPlay();
abstract void endPlay();
// 模板方法
public final void play() {
// 初始化游戏
initialize();
// 开始游戏
startPlay();
// 结束游戏
endPlay();
}
}
// 具体类
public class Cricket extends Game {
void initialize() {
System.out.println("Cricket Game Initialized! Start playing.");
}
void startPlay() {
System.out.println("Cricket Game Started. Enjoy the game!");
}
void endPlay() {
System.out.println("Cricket Game Finished!");
}
}
public class Football extends Game {
void initialize() {
System.out.println("Football Game Initialized! Start playing.");
}
void startPlay() {
System.out.println("Football Game Started. Enjoy the game!");
}
void endPlay() {
System.out.println("Football Game Finished!");
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Game cricket = new Cricket();
cricket.play();
System.out.println();
Game football = new Football();
football.play();
}
}
在上面的示例中,我们创建了一个简单的模板方法模式实现。抽象类(Game)定义了一个算法的骨架,其中包含了一些抽象方法和具体方法,具体方法由父类来实现,抽象方法由子类来实现。具体类(Cricket和Football)实现了抽象类定义的抽象方法,从而完成了游戏的具体实现。
模板方法模式适用于具有固定流程的算法,它提供了一种灵活的方式来实现算法的复用和扩展,同时保持了算法的结构不变。
11. 访问者模式 (Visitor Pattern)
访问者模式旨在封装一些作用于某种数据结构中的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新操作。访问者模式通过将数据结构与操作分离,使得新增操作更加灵活,同时符合开闭原则。
概念和作用
访问者模式的核心思想是将数据结构与操作分离,将数据结构中的元素与操作进行解耦,从而使得新增操作更加灵活。它通过定义一个访问者接口和一组具体访问者来实现作用于数据结构中各元素的操作。
结构和角色
访问者模式由两个主要角色组成:抽象访问者和具体访问者。
- 抽象访问者(Visitor):定义了作用于数据结构中各元素的操作接口,可以访问数据结构中的每个元素。
- 具体访问者(ConcreteVisitor):实现了抽象访问者定义的操作接口,并定义了具体的操作逻辑。
应用场景和实例
访问者模式常用于需要对数据结构中的元素进行多种不同操作的场景,例如编译器的语法树遍历、文件系统的访问等。
// 抽象元素
public interface Element {
void accept(Visitor visitor);
}
// 具体元素
public class ConcreteElementA implements Element {
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
public class ConcreteElementB implements Element {
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
// 抽象访问者
public interface Visitor {
void visit(ConcreteElementA element);
void visit(ConcreteElementB element);
}
// 具体访问者
public class ConcreteVisitor implements Visitor {
public void visit(ConcreteElementA element) {
System.out.println("Visitor is visiting ConcreteElementA");
}
public void visit(ConcreteElementB element) {
System.out.println("Visitor is visiting ConcreteElementB");
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Element elementA = new ConcreteElementA();
Element elementB = new ConcreteElementB();
Visitor visitor = new ConcreteVisitor();
elementA.accept(visitor);
elementB.accept(visitor);
}
}
在上面的示例中,我们创建了一个简单的访问者模式实现。抽象元素(Element)定义了作用于数据结构中各元素的操作接口,具体元素(ConcreteElementA和ConcreteElementB)实现了抽象元素定义的接口,并实现了具体的操作逻辑。抽象访问者(Visitor)定义了作用于元素的操作接口,具体访问者(ConcreteVisitor)实现了抽象访问者定义的接口,并定义了具体的操作逻辑。
访问者模式适用于需要对数据结构中的元素进行多种不同操作的场景,它通过将操作与数据结构分离,使得新增操作更加灵活,并符合开闭原则。