设计模式:行为型模式

行为型设计模式是一类设计模式,它们关注的是对象之间的相互作用,以及对象如何通过消息传递来实现松耦合。这些模式涉及到算法和对象之间职责的分配。在本文中,我们将深入探讨几种常见的行为型模式,并提供详细的解释、示例和应用场景。

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")); // trueSystem.out.println(orExpr.interpret("world")); // trueSystem.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)实现了抽象访问者定义的接口,并定义了具体的操作逻辑。

访问者模式适用于需要对数据结构中的元素进行多种不同操作的场景,它通过将操作与数据结构分离,使得新增操作更加灵活,并符合开闭原则。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/710278.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HQL,SQL刷题,尚硅谷

目录 相关表数据&#xff1a; 题目及思路解析&#xff1a; 查询结果排序&分组指定条件 1、查询学生的总成绩并按照总成绩降序排序 2、按照如下格式显示学生的语文、数学、英语三科成绩&#xff0c;没有成绩的输出为0&#xff0c;按照学生的有效平均成绩降序显示 3、查询一…

hosts.allow限制可通过SSH登录到服务器的IP

hosts.allow限制可通过SSH登录到服务器的IP 网络防火墙是阻挡非授权主机访问网络的第一道防护&#xff0c;但是它们不应该仅有一道屏障。Linux使用了两个文件!。/etc/hosts.allow和/etc/hosts.deny&#xff0c;根据网络请求的来源限制对服务的访问。 hosts.allow文件列出了允…

常用SQL查询方法与实例

目录 SELECT查询 INSERT查询 UPDATE查询 DELETE查询 JOIN查询 GROUP BY查询 HAVING查询 窗口函数 公共表表达式&#xff08;CTEs&#xff09; 递归查询 透视表 分析函数 解透视 条件聚合 日期函数 合并语句 情况语句 常用SQL查询方法有以下几种&#xff1a; S…

【无监督学习之聚类】

曾梦想执剑走天涯&#xff0c;我是程序猿【AK】 目录 简述概要知识图谱1. K-Means聚类2. 层次聚类&#xff08;Hierarchical Clustering&#xff09;3. DBSCAN&#xff08;Density-Based Spatial Clustering of Applications with Noise&#xff09;4. 谱聚类&#xff08;Spect…

一个实时波形图的封装demo(QT)(qcustomplot)

前言&#xff1a; 封装的一个实时波形图的类&#xff0c;可以直接提升使用。 提供了接口&#xff0c;可以更改颜色&#xff0c;样式&#xff0c;等等 参考&#xff1a; Qt Plotting Widget QCustomPlot - Introduction 另外参考了一个大神的作品&#xff0c;链接没找到。 项目…

前端面试练习24.2.29

一.关于Vuex说法 Vuex可以用来管理数据 Vuex也可以实现组件间的传值 mutation中的方法按照规定最好不要涉及异步方法 Vuex的属性有 state 存储状态 mutations 同步函数 actions 异步函数&#xff0c;并且调用的事mutations getters 派生状态&#xff0c;类似与vue中的c…

嘎嘎快充云快充互联互通系统使用说明书

嘎嘎快充云快充互联互通系统 V1.0.0 使用手册 &#xff08;V1.0&#xff09; 二○二四年一月 目录 一、软件产品概述 2 二、系统要求及运行环境 2 1、 系统要求 2 2、 运行环境 3 三、软件操作和说明 3 1、 软件的安装 3 2、 软件启动 8 3、 软件工作界面 8 4、 软件功能介绍…

#13Maven打包生成MD5校验文件的两种方式

目录 1、checksum-maven-plugin 2、maven-antrun-plugin 1、checksum-maven-plugin <plugin><groupId>net.ju-n.maven.plugins</groupId><artifactId>checksum-maven-plugin</artifactId><version>1.2</version><executions&g…

线路覆冰加重导线舞动风险,输电线路导线舞动在线监测装置保障运行安全

2月21日&#xff0c;山东烟台迎来强降雪天气&#xff0c;国网烟台供电公司紧急部署&#xff0c;组织运维人员联合智能巡检设备对重要变电站和输电线路进行巡视&#xff0c;确保电网安全稳定运行。 “雨雪天气给输电线路造成一定的影响&#xff0c;尤其是雨雪加上冰冻&#xff0…

NIST正式发布网络安全框架 2.0最终版:相比之前两个版本的六大重大变化

2月26日美国国家标准与技术研究院 (NIST) 正式发布了更新后的网络安全框架 (CSF)&#xff0c;这是其降低网络安全风险的里程碑式指导文件。新的 2.0 版本专为所有行业部门和组织类型而设计&#xff0c;从最小的学校和非营利组织到最大的机构和公司&#xff0c;无论其网络安全的…

Nodejs+vue汽车保养美容管理系统vscode前后端分离项目

汽车美容保养管理系统后台采用nodejs语言开发,前台页面和后台管理页面使用vue等技术开发,使用MySql作为数据持久化存储工具对汽车美容保养管理系统的用户等角色权限对应的功能等进行存储。采用vsocde集成IDE对汽车美容保养管理系统统进行开发,整合系统的各个模块。 拟开发的汽车…

Kivy和BeeWare 开发APP的优缺点,及其发展历史

Kivy和BeeWare都是流行的Python框架&#xff0c;用于开发移动应用。它们各自有独特的特点和优势&#xff0c;同时也面临一些挑战和限制。下面是对这两个框架的开发优缺点及其发展历史的总结。 Kivy 发展历史 起源&#xff1a;Kivy诞生于2010年&#xff0c;旨在提供一个用于P…

[回归指标]R2、PCC(Pearson’s r )

R2相关系数 R2相关系数很熟悉了&#xff0c;就不具体解释了。 皮尔逊相关系数&#xff08;PCC&#xff09; 皮尔逊相关系数是研究变量之间线性相关程度的量&#xff0c;R方和PCC是不同的指标。R方衡量x和y的接近程度&#xff0c;PCC衡量的是x和y的变化趋势是否相同。R方是不…

Mac OS 制作可引导安装器并重新安装系统

Mac 使用 U盘或移动固态硬盘制作可引导的安装器&#xff08;以 Monterey 为例&#xff09; 本教程参考 Apple 官网相关教程 创建可引导 Mac OS 安装器 重新安装 Mac OS 相关名词解释 磁盘分区会将其划分为多个单独的部分&#xff0c;称为分区。分区也称为容器&#xff0c;不同…

以太坊学习工具推荐

以太坊学习工具推荐 主网浏览器Sepolia测试网浏览器ETH官方网站Raw Transaction Decode Toolweb3.pyweb3.jsSolidity 学习文档

Windows PowerShell 命令行历史记录补全

Windows 命令行历史记录补全 使用 powershell 安装PSReadLine 2.1.0 Install-Module PSReadLine -RequiredVersion 2.1.0检查是否存在配置文件 Test-path $profile # 为 false 则执行命令创建 New-item –type file –force $profile编辑配置文件 notepad $profile# 输入如下…

备战蓝桥杯---树形DP基础3

上一次我们讲了二叉苹果树&#xff0c;现在我们加一点难度&#xff0c;从二叉变成了多叉苹果树。 这样子我们就不可以直接按照上次的方法DP&#xff0c;我们其实可以发现&#xff0c;我们可以用类似背包的思想求解&#xff0c;这就是所谓的树上背包。 我们先加进第一个儿子来…

鸿蒙Harmony应用开发—ArkTS声明式开发(挂载卸载事件)

挂载卸载事件指组件从组件树上挂载、卸载时触发的事件。 说明&#xff1a; 从API Version 7开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。 onAppear onAppear(event: () > void) 组件挂载显示时触发此回调。 卡片能力&#xff1a; …

如何入门深度学习

入门深度学习需要一步步学习基础知识&#xff0c;积累实践经验&#xff0c;并持续关注领域的最新进展。以下是详细的入门指南&#xff1a; 1. 掌握基本数学和编程知识&#xff1a; 线性代数&#xff1a;深度学习涉及大量矩阵运算&#xff0c;因此了解线性代数的基本概念和操作…

qt写代码判断一个数字是否可以被7整除

普通小程序cgtk可以跨平台&#xff0c;c跨平台用qt比较方便&#xff0c;deepinlinuxv20.9应用商店安装dtk-ide&#xff0c;就可以开发qt了&#xff0c;用上dtk模板就是dtk应用&#xff0c;qt模板就是qt跨平台应用 #include "mainwindow.h" #include "ui_mainwi…