行为型模式关注对象交互、通信和控制流。
一、责任链模式
一个类只做一件事,那么对于一个流程多个操作来说,就需要多个类负责不同的操作,这些类被称为处理器
责任链模式的处理方式:如果需要则处理请求,否则将请求传递给下一个处理器
角色:
客户端:发送请求,实例化一个处理器链,调用第一个对象的handleRequest方法
Handler处理器:抽象类,定义了handleRequest方法
concreteHandle具体处理器:继承自Handler,实现了handleRequest方法,每一个具体处理器都维持一个引用,只想链中下一个处理器,需要时将请求传递下去
举例:
public class HandlerChain {
// 持有所有Handler:
private List<Handler> handlers = new ArrayList<>();
public void addHandler(Handler handler) {
this.handlers.add(handler);
}
public boolean process(Request request) {
// 依次调用每个Handler:
for (Handler handler : handlers) {
Boolean r = handler.process(request);
if (r != null) {
// 如果返回TRUE或FALSE,处理结束:
System.out.println(request + " " + (r ? "Approved by " : "Denied by ") + handler.getClass().getSimpleName());
return r;
}
}
throw new RuntimeException("Could not handle request: " + request);
}
}
// 构造责任链:
HandlerChain chain = new HandlerChain();
chain.addHandler(new ManagerHandler());
chain.addHandler(new DirectorHandler());
chain.addHandler(new CEOHandler());
// 处理请求:
chain.process(new Request("Bob", new BigDecimal("123.45")));
适用情况:
日志处理器:每个处理器记录一个基于其状态的特殊请求,要么将请求传送给下一个处理器
servlet:filter用于过滤其你去或者响应,doFilter把过滤器链作为一个参数接收,可以传递请求
二、命令模式
目的:
提供一个统一的方法来封装命令和其所需要的参数来执行一个动作;
允许处理命令,例如将命令存储在队列中。
角色:
Command命令类:命令封装的抽象类,声明了execute()抽象方法
concreteCommand具体命令类:实现execute()抽象方法
receiver接收者:负责执行与命令关联的操作和类,跟concreteCommand可以是一个
invoker调用者:触发命令的类,通常外部调用
client:实例化具体命令对象及其接收者的实际类
举例:
public interface Command {
public void execute();
}
//接收者
class Receiver {
public void action1() {
System.out.println("接收者的action()方法被调用...");
}
public void action2() {
System.out.println("接收者的action()方法被调用...");
}
}
//具体命令类:
public class OpenCommand extends Command {
private Receiver receiver;
ConcreteCommand() {
receiver = new Receiver();
}
public void execute() {
receiver.action1();
}
}
public class CloseCommand extends Command {
private Receiver receiver;
ConcreteCommand() {
receiver = new Receiver();
}
public void execute() {
receiver.action2();
}
}
客户端:
public class CommandPattern {
public static void main(String[] args) {
Command cmd = new ConcreteCommand();
Invoker ir = new Invoker(cmd);
System.out.println("客户访问调用者的call()方法...");
ir.call();
}
}
//调用者
class Invoker {
private Command command;
public Invoker(Command command) {
this.command = command;
}
public void setCommand(Command command) {
this.command = command;
}
public void call() {
System.out.println("调用者执行命令command...");
command.execute();
}
}
客户端只负责决定调用哪个具体命令,命令执行execute会决定由哪个receiver去具体执行哪个action,如果只有一个receiver就不用那么麻烦了
使用情况:
多线程:
RunnalbeThread mrt = new RunnableThread();
Tread t = new Thread(mrt);
t.start();
组合命令:
听起来像责任链模式,将命令组合起来调用,这样接收者和具体命令类就不是同一个了
三、解释器模式
实际应用较少
解释器模式定义语法的表示以及该语法对应解释
解释器模式使用组合模式来定义对象结构的内部表示,另外,还添加了实现来解释表达式并将其转换为内部结构
类似于组合模式,只是组合模式是针对对象的,解释器模式是针对类的
角色:
context环境:用于封装解释器的全局信息,所有具体的解释器均需访问context
抽象表达式:声明执行的解释方法
终结符表达式:一种解释器类。实现与语法的终结符相关的操作,终结符表达式必须始终被实现和实例化,因为它表示表达式的结尾
非终结符表达式:这是实现语法的不同规则或符号的类,对于每一个语法都应该创建一个类
举例:
假如“韶粵通”公交车读卡器可以判断乘客的身份,如果是“韶关”或者“广州”的“老人” “妇女”“儿童”就可以免费乘车,其他人员乘车一次扣 2 元。
分析:要解释一个句子,得首先分析表达式expression的样式,例如中文语句由“主谓宾”构成
<expression> ::= <city>的<person>
<city> ::= 韶关|广州
<person> ::= 老人|妇女|儿童
/*文法规则
<expression> ::= <city>的<person>
<city> ::= 韶关|广州
<person> ::= 老人|妇女|儿童
*/
public class InterpreterPatternDemo {
public static void main(String[] args) {
Context bus = new Context();
bus.freeRide("韶关的老人");
bus.freeRide("韶关的年轻人");
bus.freeRide("广州的妇女");
bus.freeRide("广州的儿童");
bus.freeRide("山东的儿童");
}
}
//抽象表达式类
interface Expression {
public boolean interpret(String info);
}
//终结符表达式类
class TerminalExpression implements Expression {
private Set<String> set = new HashSet<String>();
public TerminalExpression(String[] data) {
for (int i = 0; i < data.length; i++) set.add(data[i]);
}
public boolean interpret(String info) {
return set.contains(info)
}
}
//非终结符表达式类,描述“的”
class AndExpression implements Expression {
private Expression city = null;
private Expression person = null;
public AndExpression(Expression city, Expression person) {
this.city = city;
this.person = person;
}
public boolean interpret(String info) {
String s[] = info.split("的");
return city.interpret(s[0]) && person.interpret(s[1]);
}
}
//环境类
class Context {
private String[] citys = {"韶关", "广州"};
private String[] persons = {"老人", "妇女", "儿童"};
private Expression cityPerson;
public Context() {
Expression city = new TerminalExpression(citys);
Expression person = new TerminalExpression(persons);
cityPerson = new AndExpression(city, person);
}
public void freeRide(String info) {
boolean ok = cityPerson.interpret(info);
if (ok) System.out.println("您是" + info + ",您本次乘车免费!");
else System.out.println(info + ",您不是免费人员,本次乘车扣费2元!");
}
}
应用场景:
当语言的文法较为简单,且执行效率不是关键问题时。
当问题重复出现,且可以用一种简单的语言来进行表达时。
当一个语言需要解释执行,并且语言中的句子可以表示为一个抽象语法树的时候,如 XML 文档解释。
四、迭代器模式
最广为人知的模式之一,几乎不会自己写迭代器。除非需要定制一个自己实现的数据结构对应的迭代器,否则,开源框架提供的 API 完全够用
提供一种顺序遍历集合对象元素而不暴露内部实现的方法
角色:
抽象容器、抽象迭代器、具体容器、具体迭代器
一般实现:
public interface Iterator{
public Object next();
public boolean hasNext();
}
public interface Aggregate{
public Iterator createIterator();
}
定义一个具体容器类StringArray, 实例化一个其对象strarr,就可以用:
for (Iterator it = strarr.createIterator();it.hasNext();){
system.out.println(it.next());
}
五、观察者模式(类似于kafka的消息发布-订阅模式)
许多对象并不是单独存在的,一个对象的改变可能引起其他对象的改变,例如:Excel中的数据改变,已经制成的折线图等跟着改变。观察者模式使得一个对象的状态改变时,已经登记的其他对象能够观察到这一改变,并做出相应改变。又称为发布-订阅模式,模型-视图模式
角色:
主题Subject:由类实现的可观察的接口。应通知的观察者使用attach(Observer)注册,不再需要被告知变更时,detach(Observer)取消注册
具体主题:实现主题接口,处理观察者列表并更新他们的变化
观察者Observer:接口,包含了一个更新自己的抽象方法,当接到具体主题的更改通知时被调用
具体观察者:实现抽象观察者中定义的抽象方法,以便在得到目标的更改通知时更新自身的状态。
public class ObserverPattern {
public static void main(String[] args) {
Subject subject = new ConcreteSubject();
Observer obs1 = new ConcreteObserver1();
Observer obs2 = new ConcreteObserver2();
subject.add(obs1);
subject.add(obs2);
subject.notifyObserver();
}
}
//抽象目标
abstract class Subject {
protected List<Observer> observers = new ArrayList<Observer>();
//增加观察者方法
public void add(Observer observer) {
observers.add(observer);
}
//删除观察者方法
public void remove(Observer observer) {
observers.remove(observer);
}
//通知观察者方法
//可以将要变更的内容作为参数传入方法,再传入response方法,也就是构造event去通知listener,与项目中的事件监听是一回事
//相当于项目中的publishEvent方法,只是main方法中的过程由org.springframework.context.ApplicationContext以及kafka替代
public abstract void notifyObserver();
}
//具体目标
class ConcreteSubject extends Subject {
public void notifyObserver() {
System.out.println("具体目标发生改变...");
System.out.println("--------------");
for (Object obs : observers) {
((Observer) obs).response();
}
}
}
//抽象观察者
interface Observer {
//反应
//相当于onApplicationEvent方法,每个事件listener需要实现这个方法,实现事件监听
void response();
}
//具体观察者1
class ConcreteObserver1 implements Observer {
public void response() {
System.out.println("具体观察者1作出反应!");
}
}
//具体观察者1
class ConcreteObserver2 implements Observer {
public void response() {
System.out.println("具体观察者2作出反应!");
}
}
另外,java.util.Observable和java.util.Observer已经定义了观察者模式,也可以直接继承使用
public class CrudeOilFutures {
public static void main(String[] args) {
OilFutures oil = new OilFutures();
Observer bull = new Bull(); //多方
Observer bear = new Bear(); //空方
oil.addObserver(bull);
oil.addObserver(bear);
oil.setPrice(10);
oil.setPrice(-8);
}
}
//具体目标类:原油期货
class OilFutures extends Observable {
private float price;
public float getPrice() {
return this.price;
}
public void setPrice(float price) {
super.setChanged(); //设置内部标志位,注明数据发生变化
super.notifyObservers(price); //通知观察者价格改变了
this.price = price;
}
}
//具体观察者类:多方
class Bull implements Observer {
public void update(Observable o, Object arg) {
Float price = ((Float) arg).floatValue();
if (price > 0) {
System.out.println("油价上涨" + price + "元,多方高兴了!");
} else {
System.out.println("油价下跌" + (-price) + "元,多方伤心了!");
}
}
}
//具体观察者类:空方
class Bear implements Observer {
public void update(Observable o, Object arg) {
Float price = ((Float) arg).floatValue();
if (price > 0) {
System.out.println("油价上涨" + price + "元,空方伤心了!");
} else {
System.out.println("油价下跌" + (-price) + "元,空方高兴了!");
}
}
}
六、中介者模式
定义一个中介对象来封装一系列对象之间的交互,使原有对象之间的耦合松散,且可以独立地改变它们之间的交互
角色:
抽象中介者:提供同时对象注册和转发同事对象信息的方法
具体中介者:定义一个list管理同事对象,协调各个同事角色之间的相互关系,因此依赖于同事角色
抽象同事类:保存中介对象,提供同事对象交互的方,实现所有相互影响的同事类的公共功能
具体同事类:当需要与其他同事对象交互时,由中介者负责后续的交互
public class MediatorPattern {
public static void main(String[] args) {
Mediator md = new ConcreteMediator();
Colleague c1, c2;
c1 = new ConcreteColleague1();
c2 = new ConcreteColleague2();
md.register(c1);
md.register(c2);
c1.send();
System.out.println("-------------");
c2.send();
}
}
//抽象中介者
abstract class Mediator {
public abstract void register(Colleague colleague);
public abstract void relay(Colleague cl); //转发
}
//具体中介者
class ConcreteMediator extends Mediator {
private List<Colleague> colleagues = new ArrayList<Colleague>();
public void register(Colleague colleague) {
if (!colleagues.contains(colleague)) {
colleagues.add(colleague);
colleague.setMedium(this);
}
}
public void relay(Colleague cl) {
for (Colleague ob : colleagues) {
if (!ob.equals(cl)) {
((Colleague) ob).receive();
}
}
}
}
//抽象同事类
abstract class Colleague {
protected Mediator mediator;
public void setMedium(Mediator mediator) {
this.mediator = mediator;
}
public abstract void receive();
public abstract void send();
}
//具体同事类
class ConcreteColleague1 extends Colleague {
public void receive() {
System.out.println("具体同事类1收到请求。");
}
public void send() {
System.out.println("具体同事类1发出请求。");
mediator.relay(this); //请中介者转发
}
}
//具体同事类
class ConcreteColleague2 extends Colleague {
public void receive() {
System.out.println("具体同事类2收到请求。");
}
public void send() {
System.out.println("具体同事类2发出请求。");
mediator.relay(this); //请中介者转发
}
}
应用:微信双方发消息,微信的服务器就是一个中介者
扩展:
1.不定义中介者接口,把具体中介者对象实现成为单例。
2.同事对象不持有中介者,而是在需要的时候直接获取中介者单例对象并调用。
//简单单例中介者
class SimpleMediator {
private static SimpleMediator smd = new SimpleMediator();
private List<SimpleColleague> colleagues = new ArrayList<SimpleColleague>();
private SimpleMediator() {
}
public static SimpleMediator getMedium() {
return (smd);
}
public void register(SimpleColleague colleague) {
if (!colleagues.contains(colleague)) {
colleagues.add(colleague);
}
}
public void relay(SimpleColleague scl) {
for (SimpleColleague ob : colleagues) {
if (!ob.equals(scl)) {
((SimpleColleague) ob).receive();
}
}
}
}
//抽象同事类
interface SimpleColleague {
void receive();
void send();
}
//具体同事类
class SimpleConcreteColleague1 implements SimpleColleague {
SimpleConcreteColleague1() {
SimpleMediator smd = SimpleMediator.getMedium();
smd.register(this);
}
public void receive() {
System.out.println("具体同事类1:收到请求。");
}
public void send() {
SimpleMediator smd = SimpleMediator.getMedium();
System.out.println("具体同事类1:发出请求...");
smd.relay(this); //请中介者转发
}
}
七、备忘录模式
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便以后当需要时能将该对象恢复到原先保存的状态。该模式又叫快照模式。
应用:Ctrl+Z,事务处理
角色:
发起人(Originator)角色:记录当前时刻的内部状态信息,提供创建备忘录和恢复备忘录数据的功能,实现其他业务功能,它可以访问备忘录里的所有信息。
备忘录(Memento)角色:负责存储发起人的内部状态,在需要的时候提供这些内部状态给发起人。
管理者(Caretaker)角色:对备忘录进行管理,提供保存与获取备忘录的功能,但其不能对备忘录的内容进行访问与修改。
public class MementoPattern {
public static void main(String[] args) {
Originator or = new Originator();
Caretaker cr = new Caretaker();
or.setState("S0");
System.out.println("初始状态:" + or.getState());
cr.setMemento(or.createMemento()); //保存状态
or.setState("S1");
System.out.println("新的状态:" + or.getState());
or.restoreMemento(cr.getMemento()); //恢复状态
System.out.println("恢复状态:" + or.getState());
}
}
//备忘录
class Memento {
private String state;
public Memento(String state) {
this.state = state;
}
public void setState(String state) {
this.state = state;
}
public String getState() {
return state;
}
}
//发起人
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 m) {
this.setState(m.getState());
}
}
//管理者
class Caretaker {
private Memento memento;
public void setMemento(Memento m) {
memento = m;
}
public Memento getMemento() {
return memento;
}
}
八、状态模式
根据不同的状态做出不同的行为,常见的switch case,if else
状态模式思想:当控制一个对象状态转换的条件表达式过于复杂时,把相关“判断逻辑”提取出来,用各个不同的类进行表示,系统处于哪种情况,直接使用相应的状态类对象进行处理
角色:
环境类(Context)角色:也称为上下文,它定义了客户端需要的接口,内部维护一个当前状态,并负责具体状态的切换。
抽象状态(State)角色:定义一个接口,用以封装环境对象中的特定状态所对应的行为,可以有一个或多个行为。
具体状态(Concrete State)角色:实现抽象状态所对应的行为,并且在需要的情况下进行状态切换。
public class StatePatternClient {
public static void main(String[] args) {
Context context = new Context(); //创建环境
context.Handle(); //处理请求
context.Handle();
context.Handle();
context.Handle();
}
}
//环境类
class Context {
private State state;
//定义环境类的初始状态
public Context() {
this.state = new ConcreteStateA();
}
//设置新状态
public void setState(State state) {
this.state = state;
}
//读取状态
public State getState() {
return (state);
}
//对请求做处理
public void Handle() {
state.Handle(this);
}
}
//抽象状态类
abstract class State {
public abstract void Handle(Context context);
}
//具体状态A类
class ConcreteStateA extends State {
public void Handle(Context context) {
System.out.println("当前状态是 A.");
context.setState(new ConcreteStateB());
}
}
//具体状态B类
class ConcreteStateB extends State {
public void Handle(Context context) {
System.out.println("当前状态是 B.");
context.setState(new ConcreteStateA());
}
}
九、策略模式
当实现某一个功能存在多种算法或者策略,我们可以根据环境或者条件的不同选择不同的算法或者策略来完成该功能,如数据排序策略有冒泡排序、选择排序、插入排序、二叉树排序等。
定义:该模式定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户。策略模式属于对象行为模式,它通过对算法进行封装,把使用算法的责任和算法的实现分割开来,并委派给不同的对象对这些算法进行管理。
角色:
抽象策略(Strategy)类:定义了一个公共接口,各种不同的算法以不同的方式实现这个接口,环境角色使用这个接口调用不同的算法,一般使用接口或抽象类实现。
具体策略(Concrete Strategy)类:实现了抽象策略定义的接口,提供具体的算法实现。
环境(Context)类:持有一个策略类的引用,最终给客户端调用。
public class StrategyPattern {
public static void main(String[] args) {
Context c = new Context();
Strategy s = new ConcreteStrategyA();
c.setStrategy(s);
c.strategyMethod();
System.out.println("-----------------");
s = new ConcreteStrategyB();
c.setStrategy(s);
c.strategyMethod();
}
}
//抽象策略类
interface Strategy {
public void strategyMethod(); //策略方法
}
//具体策略类A
class ConcreteStrategyA implements Strategy {
public void strategyMethod() {
System.out.println("具体策略A的策略方法被访问!");
}
}
//具体策略类B
class ConcreteStrategyB implements Strategy {
public void strategyMethod() {
System.out.println("具体策略B的策略方法被访问!");
}
}
//环境类
class Context {
private Strategy strategy;
public Strategy getStrategy() {
return strategy;
}
public void setStrategy(Strategy strategy) {
this.strategy = strategy;
}
public void strategyMethod() {
strategy.strategyMethod();
}
}
状态模式和策略模式很相似。状态模式将各个状态所对应的操作分离开来,即对于不同的状态,由不同的子类实现具体操作,不同状态的切换由子类实现,当发现传入参数不是自己这个状态所对应的参数,则自己给Context类切换状态;而策略模式是直接依赖注入到Context类的参数进行选择策略,不存在切换状态的操作。
十、模板方法模式
设计一个系统时知道了算法所需的关键步骤,而且确定了这些步骤的执行顺序,但某些步骤的具体实现还未知,或者说某些步骤的实现与具体的环境相关。
定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤
角色:
抽象类/抽象模板:模板方法定义算法的骨架;模板方法中调用的每一步方法称为基本方法,包括三种:抽象方法(由子类事先)、具体方法(已经实现,子类也可以重写)、钩子方法(已经实现,包括用于判断的逻辑方法和需要子类重写的空方法两种)
具体类/方法:实现抽象方法和钩子方法
public class TemplateMethodPattern {
public static void main(String[] args) {
AbstractClass tm = new ConcreteClass();
tm.TemplateMethod();
}
}
//抽象类
abstract class AbstractClass {
//模板方法
public void TemplateMethod() {
SpecificMethod();
abstractMethod1();
abstractMethod2();
}
//具体方法
public void SpecificMethod() {
System.out.println("抽象类中的具体方法被调用...");
}
//抽象方法1
public abstract void abstractMethod1();
//抽象方法2
public abstract void abstractMethod2();
}
//具体子类
class ConcreteClass extends AbstractClass {
public void abstractMethod1() {
System.out.println("抽象方法1的实现被调用...");
}
public void abstractMethod2() {
System.out.println("抽象方法2的实现被调用...");
}
}
扩展:带钩子方法的模板方法模式
public class HookTemplateMethod {
public static void main(String[] args) {
HookAbstractClass tm = new HookConcreteClass();
tm.TemplateMethod();
}
}
//含钩子方法的抽象类
abstract class HookAbstractClass {
//模板方法
public void TemplateMethod() {
abstractMethod1();
HookMethod1();
if (HookMethod2()) {
SpecificMethod();
}
abstractMethod2();
}
//具体方法
public void SpecificMethod() {
System.out.println("抽象类中的具体方法被调用...");
}
//钩子方法1
public void HookMethod1() {
}
//钩子方法2
public boolean HookMethod2() {
return true;
}
//抽象方法1
public abstract void abstractMethod1();
//抽象方法2
public abstract void abstractMethod2();
}
//含钩子方法的具体子类
class HookConcreteClass extends HookAbstractClass {
public void abstractMethod1() {
System.out.println("抽象方法1的实现被调用...");
}
public void abstractMethod2() {
System.out.println("抽象方法2的实现被调用...");
}
public void HookMethod1() {
System.out.println("钩子方法1被重写...");
}
public boolean HookMethod2() {
return false;
}
}
十一、访问者模式
主要将数据结构与数据操作分离。
设计模式中最复杂的一个,但日常开发中使用频率却不高
适用情况:一个类中有很多中元素,类结构稳定,不会频繁增删不同类型的元素,而经常需要给这些元素增加新的操作时,考虑这种模式
角色:
Element(元素):抽象类,必须声明一个accept(Visitor visitor)方法
ConcreteElement(具体元素):实现element及其accept方法
Visitor(访问者):抽象类,其中声明了一系列与元素对应的visit(Element)方法, 一般一个元素一个visit方法
ConcreteVisitor(具体访问者):实现visitor
ObjectStructure:对象结构,对象结构包含各种元素,要求元素稳定,且可以迭代访问这些元素(例如农场类,里面有各种动植物元素)
//抽象元素
public interface ComputerPart {
public void accept(ComputerPartVisitor computerPartVisitor);
}
//具体类1-键盘类
public class Keyboard implements ComputerPart {
@Override
public void accept(ComputerPartVisitor computerPartVisitor) {
computerPartVisitor.visit(this);
}
}
//具体类2-显示器类
public class Monitor implements ComputerPart {
@Override
public void accept(ComputerPartVisitor computerPartVisitor) {
computerPartVisitor.visit(this);
}
}
//具体类3-鼠标类
public class Mouse implements ComputerPart {
@Override
public void accept(ComputerPartVisitor computerPartVisitor) {
computerPartVisitor.visit(this);
}
}
//具体类4-电脑类
public class Computer implements ComputerPart {
ComputerPart[] parts;
public Computer(){
parts = new ComputerPart[] {new Mouse(), new Keyboard(), new Monitor()};
}
@Override
public void accept(ComputerPartVisitor computerPartVisitor) {
for (int i = 0; i < parts.length; i++) {
parts[i].accept(computerPartVisitor);
}
computerPartVisitor.visit(this);
}
}
//抽象visitor类,每个元素一个visit方法
public interface ComputerPartVisitor {
public void visit(Computer computer);
public void visit(Mouse mouse);
public void visit(Keyboard keyboard);
public void visit(Monitor monitor);
}
//具体visitor类
public class ComputerPartDisplayVisitor implements ComputerPartVisitor {
@Override
public void visit(Computer computer) {
System.out.println("Displaying Computer.");
}
@Override
public void visit(Mouse mouse) {
System.out.println("Displaying Mouse.");
}
@Override
public void visit(Keyboard keyboard) {
System.out.println("Displaying Keyboard.");
}
@Override
public void visit(Monitor monitor) {
System.out.println("Displaying Monitor.");
}
}
//客户端代码
public class VisitorPatternDemo {
public static void main(String[] args) {
ComputerPart computer = new Computer();
computer.accept(new ComputerPartDisplayVisitor());
}
}