文章目录
- 一、访问者模式简介
- 二、访问者模式 适用场景
- 三、访问者模式 优缺点
- 四、访问者模式 与 迭代器模式
- 五、代码示例
- 1、Game 父类 ( 被访问者 )
- 2、VipGame 收费游戏 ( 被访问者 )
- 3、FreeGame 免费游戏 ( 被访问者 )
- 4、IVisitor 访问者接口
- 5、VipVisitor 付费玩家
- 6、测试类
一、访问者模式简介
访问者模式 : 封装 作用于 某种 数据结构 的 各元素 操作 , 数据结构指的是 List , Set , Map 等 ;
在 不改变 元素类 的前提下 , 定义 作用于 元素 的操作 ;
访问者模式类型 : 行为型 ;
二、访问者模式 适用场景
访问者模式 适用场景 :
- List , Set , Map 等 数据结构 中 , 包含 很多类型的对象 ;
- 数据结构 与 数据操作 分离 ;
三、访问者模式 优缺点
访问者模式 优点 : 访问者模式 增加新的操作 很容易 , 只需要增加一个新的 访问者 即可 ; 将相关的行为 , 封装到一个 访问者 中 ;
访问者模式 缺点 :
- 增加 新 数据结构 比较困难 ;
- 元素变更 比较困难 ; 如 为 被访问 的对象 增加 / 减少 一些属性 , 相应的 访问者 也需要进行修改 ;
四、访问者模式 与 迭代器模式
访问者模式 与 迭代器模式 都是在 某种 数据结构 ( List / Set / Map ) 上进行处理 ;
访问者模式 主要用于 对 保存在 数据结构 中元素 , 进行某种特定处理 , 重点是 处理 ;
迭代器模式 主要作用就是 遍历 数据结构 中的元素 , 重点是 遍历 ;
五、代码示例
游戏 分为 免费游戏 和 收费游戏 , 玩家 分为 免费玩家 和 付费玩家 ;
不同的玩家 , 访问不同的游戏 , 各自有不同的效果 ;
被访问者 , 都继承自同一个父类 , 可以放在一个集合中 ;
访问者 , 都实现同一个接口 , 针对每个类型的被访问者 , 都有一个对应的重载方法 ;
如 : 玩家访问者 , 对免费游戏有一个方法 , 对收费游戏也有一个方法 ;
该设计模式不常用 , 如果遇到 数据加载 与 数据操作 分离的情况 , 可以考虑使用 访问者模式 ;
大部分情况下 , 用不到 , 但是一旦需要用到的时候 , 访问者模式是唯一的解决方案 ;
1、Game 父类 ( 被访问者 )
代码语言:javascript复制package visitor;
/**
* 游戏父类 , 所有的游戏都要继承该类
* VipGame 和 FreeGame 都继承 Game , 这两个都是 Game
*
*/
public abstract class Game {
/**
* 游戏名称
*/
private String mGameName;
public String getGameName() {
return mGameName;
}
public void setGameName(String gameName) {
this.mGameName = gameName;
}
/**
* 当有访问者要访问游戏时 , 将访问者传入该方法
* 用于判定访问者是否有权限访问游戏
* @param visitor
*/
public abstract void accept(IVisitor visitor);
}
2、VipGame 收费游戏 ( 被访问者 )
代码语言:javascript复制package visitor;
public class VipVisitor implements IVisitor {
/**
* 访问免费游戏 , 打印游戏名称
* @param freeGame
*/
@Override
public void visit(FreeGame freeGame) {
System.out.println("我是 VIP , 可以访问免费游戏 : " freeGame.getGameName());
}
/**
* 访问收费游戏 , 打印游戏名称和价格
* @param vipGame
*/
@Override
public void visit(VipGame vipGame) {
System.out.println("我是 VIP , 可以访问收费游戏 : " vipGame.getGameName() " , 价格 : " vipGame.getmVipPrice());
}
}
3、FreeGame 免费游戏 ( 被访问者 )
代码语言:javascript复制package visitor;
/**
* 免费游戏
*/
public class FreeGame extends Game {
@Override
public void accept(IVisitor visitor) {
visitor.visit(this);
}
}
4、IVisitor 访问者接口
代码语言:javascript复制package visitor;
/**
* 该接口中声明了两个重载方法
* 访问 FreeGame 的 visit 方法
* 访问 VipGame 的 visit 方法
*
* 在 Game 中调用 visit 方法 , 将自身传递到 visit 方法作为参数
* 分别调用不同的重载方法
*
* 访问者可以扩展很多了 , 可以定义若干实现了 IVisitor 接口的访问者
* 每个 Visistor 访问者 , 访问不同的游戏 , 有不同的表现 , 如 :
* 白嫖访问者 , 不花钱 , 只能玩免费游戏 , 不能玩收费游戏
* 付费访问者 , 购买 VIP , 可以同时玩免费和收费游戏
*
* 对于免费游戏来说 , 传入任何访问者都可以访问 ;
* 对于收费游戏来说 , 传入付费访问者, 才可以访问 ;
*
* 相同的 Visitor 对不同的数据产生不同的行为
* 不同的 Visitor 对相同的数据产生不同的行为
*/
public interface IVisitor {
/**
* 访问免费游戏
* @param freeGame
*/
void visit(FreeGame freeGame);
/**
* 访问收费游戏
* @param vipGame
*/
void visit(VipGame vipGame);
}
5、VipVisitor 付费玩家
代码语言:javascript复制package visitor;
public class VipVisitor implements IVisitor {
/**
* 访问免费游戏 , 打印游戏名称
* @param freeGame
*/
@Override
public void visit(FreeGame freeGame) {
System.out.println("我是 VIP , 可以访问免费游戏 : " freeGame.getGameName());
}
/**
* 访问收费游戏 , 打印游戏名称和价格
* @param vipGame
*/
@Override
public void visit(VipGame vipGame) {
System.out.println("我是 VIP , 可以访问收费游戏 : " vipGame.getGameName() " , 价格 : " vipGame.getmVipPrice());
}
}
6、测试类
代码语言:javascript复制package visitor;
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
// 创建存放 Game 的集合
ArrayList<Game> games = new ArrayList<>();
// 创建免费游戏
FreeGame freeGame = new FreeGame();
freeGame.setGameName("超级马里奥");
games.add(freeGame);
// 创建收费游戏
VipGame vipGame = new VipGame();
vipGame.setGameName("绝地求生");
vipGame.setmVipPrice(88);
games.add(vipGame);
// Vip 访问者访问免费和收费游戏
for (Game game : games) {
game.accept(new VipVisitor());
}
}
}
运行结果 :