访问者模式:封装一些作用于某种数据结构中各元素的操作,在不改变元素结构的前提下可以上元素提供新功能。
大概的意思就是说,有一个数据结构,它里面有几个元素,这是固定的,但是呢又需要在不同的情况下提供不同的功能,这时候我们就使用访问者模式,我们引入一个访问者的角色,通过一个组合把之前的数据结构和这个访问者组合一下,而在访问者中就会根据不同的场景让各个元素提供不同的方法。
举个例子,我开了一家电影院(某种数据结构),提供两种服务(内部的固定的元素):看电影、吃东西。但是我除了像提供普通的电影院的服务之外还想提供更加具体的服务,比如有vip和svip的服务,虽然基本服务还是看电影和吃东西,但是提供的环境,电影的质量,吃的东西肯定是不同的。
代码实现一下。
首先是固定元素:
// 元素类型,为了统一元素的方法,accept方法是为了接受一个访问者,而具体的房里逻辑在访问者中实现
public interface Corporate {
void accept(Visitor visitor);
}
// 具体的元素:看电影、吃东西
public class FilmCorporate implements Corporate{
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
public class FoodCorporate implements Corporate{
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
某种数据结构,包含了一些具体的元素
public class SomeMovieTheater {
// 内部元素是固定的
private FilmCorporate film;
private FoodCorporate food;
public SomeMovieTheater(FilmCorporate film, FoodCorporate food) {
this.film = film;
this.food = food;
}
// 提供服务
public void welcome(Visitor visitor){
System.out.println("顾客的身份:" + visitor.type());
System.out.print("看电影了:");
film.accept(visitor);
System.out.print("吃点儿东西吧:");
food.accept(visitor);
}
}
访问者,在访问者中,提供了针对前面几种元素的重载方法
public interface Visitor {
String type();
void visit(FilmCorporate file);
void visit(FoodCorporate food);
}
不同的访问者,实现不同的逻辑
public class CommonVisitor implements Visitor{
@Override
public String type() {
return "普通客户";
}
@Override
public void visit(FilmCorporate file) {
System.out.println("大厅里随便坐");
}
@Override
public void visit(FoodCorporate food) {
System.out.println("门口的爆米花自己拿着吃吧");
}
}
public class VipVisitor implements Visitor{
@Override
public String type() {
return "vip";
}
@Override
public void visit(FilmCorporate file) {
System.out.println("你是vip用户,前面的vip包房可以随意使用,而且咱们用的还是高清屏幕");
}
@Override
public void visit(FoodCorporate food) {
System.out.println("vip可以点任意外卖,我们有专人处理");
}
}
public class SvipVisitor implements Visitor{
@Override
public String type() {
return "SVIP";
}
@Override
public void visit(FilmCorporate file) {
System.out.println("尊敬的svip用户,请到咱们的专属包房");
}
@Override
public void visit(FoodCorporate food) {
System.out.println("你是svip了,想吃什么随便说,咱给您现做");
}
}
测试:
public class Client {
public static void main(String[] args) {
SomeMovieTheater movieTheater = new SomeMovieTheater(new FilmCorporate(), new FoodCorporate());
// 普通用户
CommonVisitor common = new CommonVisitor();
// vip用户
VipVisitor vip = new VipVisitor();
// svip用户
SvipVisitor svip = new SvipVisitor();
// 提供服务
System.out.println("开门营业了");
System.out.println("------------------");
movieTheater.welcome(common);
System.out.println("------------------");
movieTheater.welcome(vip);
System.out.println("------------------");
movieTheater.welcome(svip);
}
}
访问者模式使用的不多,条件比较严格,最明显的就是提供服务的元素是固定的,如果这个元素发生变化,必须同时修改访问者的代码,不利于程序的扩展性。而且访问者模式给我一种比较奇怪的感觉,因为正常来说,根据不同的服务对象提供对应的服务内容,通常来说是服务提供者的事情,对应到这个例子中应该就是film和food应该要做的事情,但是现在却是通过调用访问者的重载方法来实现。感觉还是理解不够。