【行为型之访问者模式】游戏开发实战——Unity灵活数据操作与跨系统交互的架构秘诀

文章目录

      • 🧳 访问者模式(Visitor Pattern)深度解析
        • 一、模式本质与核心价值
        • 二、经典UML结构
        • 三、Unity实战代码(游戏物品系统)
          • 1. 定义元素与访问者接口
          • 2. 实现具体元素类
          • 3. 实现具体访问者
          • 4. 对象结构管理
          • 5. 客户端使用
        • 四、模式进阶技巧
          • 1. 动态访问者注册
          • 2. 访问者组合模式
          • 3. 异步访问处理
        • 五、游戏开发典型应用场景
        • 六、性能优化策略
        • 七、模式对比与选择
        • 八、最佳实践原则
        • 九、常见问题解决方案

🧳 访问者模式(Visitor Pattern)深度解析

——以Unity实现灵活数据操作跨系统交互为核心案例


一、模式本质与核心价值

核心目标
分离数据结构与数据操作,支持在不修改元素类的前提下定义新操作
集中相关操作,避免污染元素类代码
实现双重分派,动态选择元素处理方法

关键术语

  • Visitor(访问者接口):声明访问各类元素的接口
  • ConcreteVisitor(具体访问者):实现特定操作的访问逻辑
  • Element(元素接口):定义接受访问者的方法
  • ObjectStructure(对象结构):维护元素集合,提供遍历接口

数学表达
设元素集合E = {e₁, e₂, …, eₙ},访问者V,则操作执行过程为:
∀e ∈ E, e.Accept(V) → V.Visit(e)


二、经典UML结构
accept
accept
«interface»
IVisitor
+VisitWeapon(Weapon)
+VisitPotion(Potion)
DamageCalculator
+VisitWeapon()
+VisitPotion()
«interface»
IItem
+Accept(IVisitor)
Weapon
+Accept()
Potion
+Accept()

三、Unity实战代码(游戏物品系统)
1. 定义元素与访问者接口
public interface IItem {void Accept(IItemVisitor visitor);
}public interface IItemVisitor {void Visit(Weapon weapon);void Visit(Potion potion);void Visit(QuestItem questItem);
}
2. 实现具体元素类
public class Weapon : MonoBehaviour, IItem {public int Damage;public string ElementType;public void Accept(IItemVisitor visitor) {visitor.Visit(this);}
}public class Potion : MonoBehaviour, IItem {public float HealAmount;public int Charges;public void Accept(IItemVisitor visitor) {visitor.Visit(this);}
}
3. 实现具体访问者
// 伤害计算访问者
public class DamageCalculator : IItemVisitor {private float _totalDamage;public void Visit(Weapon weapon) {_totalDamage += weapon.Damage * (weapon.ElementType == "Fire" ? 1.2f : 1f);}public void Visit(Potion potion) {// 药水不贡献伤害}public void Visit(QuestItem questItem) {// 任务物品不贡献伤害}public float GetTotalDamage() => _totalDamage;
}// 存档序列化访问者
public class SaveVisitor : IItemVisitor {private List<byte[]> _serializedData = new();public void Visit(Weapon weapon) {var data = Encoding.UTF8.GetBytes($"Weapon|{weapon.Damage}|{weapon.ElementType}");_serializedData.Add(data);}public void Visit(Potion potion) {var data = Encoding.UTF8.GetBytes($"Potion|{potion.HealAmount}|{potion.Charges}");_serializedData.Add(data);}public byte[] GetSaveData() {return _serializedData.SelectMany(arr => arr).ToArray();}
}
4. 对象结构管理
public class InventorySystem : MonoBehaviour {private List<IItem> _items = new();public void AddItem(IItem item) => _items.Add(item);public void ProcessItems(IItemVisitor visitor) {foreach(var item in _items) {item.Accept(visitor);}}
}
5. 客户端使用
public class GameManager : MonoBehaviour {[SerializeField] private InventorySystem _inventory;void Start() {// 计算总伤害var damageCalc = new DamageCalculator();_inventory.ProcessItems(damageCalc);Debug.Log($"总伤害值:{damageCalc.GetTotalDamage()}");// 生成存档数据var saver = new SaveVisitor();_inventory.ProcessItems(saver);SaveToFile(saver.GetSaveData());}
}

四、模式进阶技巧
1. 动态访问者注册
public class DynamicVisitor : IItemVisitor {private Dictionary<Type, Action<object>> _handlers = new();public void RegisterHandler<T>(Action<T> handler) where T : IItem {_handlers[typeof(T)] = obj => handler((T)obj);}public void Visit(Weapon weapon) => InvokeHandler(weapon);public void Visit(Potion potion) => InvokeHandler(potion);private void InvokeHandler<T>(T item) where T : IItem {if(_handlers.TryGetValue(typeof(T), out var handler)) {handler(item);}}
}
2. 访问者组合模式
public class CompositeVisitor : IItemVisitor {private List<IItemVisitor> _visitors = new();public void AddVisitor(IItemVisitor visitor) => _visitors.Add(visitor);public void Visit(Weapon weapon) {foreach(var v in _visitors) v.Visit(weapon);}public void Visit(Potion potion) {foreach(var v in _visitors) v.Visit(potion);}
}
3. 异步访问处理
public class AsyncVisitor : MonoBehaviour, IItemVisitor {public async Task ProcessAsync(InventorySystem inventory) {var tasks = new List<Task>();foreach(var item in inventory.Items) {tasks.Add(Task.Run(() => item.Accept(this)));}await Task.WhenAll(tasks);}public void Visit(Weapon weapon) {// 异步处理武器}
}

五、游戏开发典型应用场景
  1. 成就系统触发

    public class AchievementVisitor : IItemVisitor {public void Visit(Weapon w) {if(w.Damage > 100) Unlock("POWER_WEAPON");}
    }
    
  2. 战斗伤害计算

    public class BattleDamageVisitor : IItemVisitor {private float _totalDamage;public void Visit(Weapon w) {_totalDamage += CalculateElementDamage(w);}
    }
    
  3. 场景序列化存档

    public class SceneSaveVisitor : IItemVisitor {private List<SerializableData> _sceneData = new();public void Visit(Enemy e) {_sceneData.Add(new EnemyData(e.Position, e.Health));}
    }
    
  4. UI数据绑定

    public class UIDataVisitor : IItemVisitor {public void Visit(Weapon w) {InventoryUI.UpdateWeaponSlot(w);}
    }
    

六、性能优化策略
策略实现方式适用场景
访问缓存缓存频繁访问结果复杂计算场景
批处理合并多个访问操作大量元素遍历
并行处理使用Job System并行访问CPU密集型操作
惰性求值延迟执行非关键访问性能敏感场景

七、模式对比与选择
维度访问者模式策略模式
关注点跨类操作算法替换
扩展方向新增操作新增算法
元素稳定性元素类需稳定策略可任意扩展
典型应用数据序列化战斗计算

八、最佳实践原则
  1. 元素接口稳定:避免频繁修改元素类接口
  2. 访问者单一职责:每个访问者专注一个功能领域
  3. 防御性访问:处理未知元素类型
    public class SafeVisitor : IItemVisitor {public void Visit(IItem item) {if(item is Weapon w) VisitWeapon(w);else Debug.LogWarning($"未知物品类型:{item.GetType()}");}
    }
    
  4. 访问顺序控制
    public void ProcessItems(IItemVisitor visitor) {// 按优先级排序处理foreach(var item in _items.OrderBy(i => i.Priority)) {item.Accept(visitor);}
    }
    

九、常见问题解决方案

Q1:如何处理新增元素类型?
→ 使用反射扩展访问者

public class ReflectionVisitor {private Dictionary<Type, MethodInfo> _methods = new();public void Visit(IItem item) {var type = item.GetType();if(_methods.TryGetValue(type, out var method)) {method.Invoke(this, new[]{item});}}
}

Q2:如何避免循环依赖?
→ 引入中间接口层

public interface IWeaponVisitor {void VisitWeapon(Weapon weapon);
}public class DamageCalculator : IItemVisitor, IWeaponVisitor {public void Visit(Weapon w) => VisitWeapon(w);public void VisitWeapon(Weapon w) { /* 具体逻辑 */ }
}

Q3:如何调试复杂访问流程?
→ 实现访问日志代理

public class LoggingVisitorProxy : IItemVisitor {private IItemVisitor _wrapped;public void Visit(Weapon w) {Debug.Log($"开始处理武器:{w.Name}");_wrapped.Visit(w);Debug.Log("武器处理完成");}
}

上一篇 【行为型之模板方法模式】游戏开发实战——Unity标准化流程与可扩展架构的核心实现

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

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

相关文章

SQL:MySQL函数:日期函数(Date Functions)

目录 时间是数据的一种类型 &#x1f9f0; MySQL 常用时间函数大全 &#x1f7e6; 1. 获取当前时间/日期 &#x1f7e6; 2. 日期运算&#xff08;加减&#xff09; &#x1f7e6; 3. 时间差计算 &#x1f7e6; 4. 格式化日期 &#x1f7e6; 5. 提取时间部分 &#x1f7…

【MySQL】数据表更新数据

个人主页&#xff1a;Guiat 归属专栏&#xff1a;MySQL 文章目录 1. 数据更新基础1.1 更新操作的重要性1.2 更新语句基本结构1.3 更新操作注意事项 2. 基本更新操作2.1 基本UPDATE语法2.2 使用表达式更新数据2.3 使用LIMIT限制更新行数2.4 NULL值处理 3. 高级更新技术3.1 使用子…

【更新】全国省市县-公开手机基站数据集(2006-2025.3)

手机基站是现代通信网络中的重要组成部分&#xff0c;它们为广泛的通信服务提供基础设施。随着数字化进程的不断推进&#xff0c;手机基站的建设与布局对优化网络质量和提升通信服务水平起着至关重要的作用&#xff0c;本分享数据可帮助分析移动通信网络的发展和优化。本次数据…

蓝桥杯12届国B 纯质数

题目描述 如果一个正整数只有 1 和它本身两个约数&#xff0c;则称为一个质数&#xff08;又称素数&#xff09;。 前几个质数是&#xff1a;2,3,5,7,11,13,17,19,23,29,31,37,⋅⋅⋅ 。 如果一个质数的所有十进制数位都是质数&#xff0c;我们称它为纯质数。例如&#xff1…

腾讯多模态定制化视频生成框架:HunyuanCustom

HunyuanCustom 速读 一、引言 HunyuanCustom 是由腾讯团队提出的一款多模态定制化视频生成框架。该框架旨在解决现有视频生成方法在身份一致性(identity consistency)和输入模态有限性方面的不足。通过支持图像、音频、视频和文本等多种条件输入&#xff0c;HunyuanCustom 能…

力扣top100 矩阵置零

开辟数组来标记元素为0的行和列&#xff0c;然后将对应的行和列的元素全部置为0&#xff1b; class Solution { public:void setZeroes(vector<vector<int>>& matrix) {int n matrix.size();int m matrix[0].size();vector<int> l(m),r(n);for(int i …

Python知识框架

一、Python基础语法 变量与数据类型 变量命名规则 基本类型&#xff1a;int, float, str, bool, None 复合类型&#xff1a;list, tuple, dict, set 类型转换与检查&#xff08;type(), isinstance()&#xff09; 运算符 算术运算符&#xff1a;, -, *, /, //, %, ** 比较…

华为OD机试真题——单词接龙(首字母接龙)(2025A卷:100分)Java/python/JavaScript/C/C++/GO最佳实现

2025 A卷 100分 题型 本专栏内全部题目均提供Java、python、JavaScript、C、C++、GO六种语言的最佳实现方式; 并且每种语言均涵盖详细的问题分析、解题思路、代码实现、代码详解、3个测试用例以及综合分析; 本文收录于专栏:《2025华为OD真题目录+全流程解析+备考攻略+经验分…

微信小程序智能商城系统(uniapp+Springboot后端+vue管理端)

一、系统介绍 本智能商城系统是基于当今主流技术栈开发的一款多端商城解决方案&#xff0c;主要包括微信小程序前端、SpringBoot 后端服务以及 Vue 管理后台三大部分。系统融合了线上商城的核心功能&#xff0c;支持商品浏览、下单、支付、订单管理等操作&#xff0c;适用于中小…

Python笔记:c++内嵌python,c++主窗口如何传递给脚本中的QDialog,使用的是pybind11

1. 问题描述 用的是python 3.8.20, qt版本使用的是5.15.2, PySide的版本是5.15.2, pybind11的版本为2.13.6 网上说在python脚本中直接用PySide2自带的QWinWidget&#xff0c;如from PySide2.QtWinExtras import QWinWidget&#xff0c;但我用的版本中说没有QWinWidget&#x…

软考软件设计师中级——软件工程笔记

1.软件过程 1.1能力成熟度模型&#xff08;CMM&#xff09; 软件能力成熟度模型&#xff08;CMM&#xff09;将软件过程改进分为以下五个成熟度级别&#xff0c;每个级别都定义了特定的过程特征和目标&#xff1a; 初始级 (Initial)&#xff1a; 软件开发过程杂乱无章&#xf…

C# SQLite基本使用示例

目录 1 基本使用流程 1.1 步骤1&#xff1a;添加SQLite依赖 1.2 ​步骤2&#xff1a;建立连接 1.3 步骤3&#xff1a;执行SQL命令 1.4 步骤4&#xff1a;查询数据 1.5 步骤5&#xff1a;使用事务 2 SQLite基本使用示例 2.1 准备工作 2.2 完整示例 2.3 案例代码解析 …

视频图像压缩领域中 DCT 的 DC 系数和 AC 系数详解

引言 在数字图像与视频压缩领域&#xff0c;离散余弦变换&#xff08;Discrete Cosine Transform, DCT&#xff09;凭借其卓越的能量集中特性&#xff0c;成为JPEG、MPEG等国际标准的核心技术。DCT通过将空域信号映射到频域&#xff0c;分离出DC系数&#xff08;直流分量&…

对抗系统熵增:从被动救火到主动防御的稳定性实战

&#x1f4d5;我是廖志伟&#xff0c;一名Java开发工程师、《Java项目实战——深入理解大型互联网企业通用技术》&#xff08;基础篇&#xff09;、&#xff08;进阶篇&#xff09;、&#xff08;架构篇&#xff09;清华大学出版社签约作家、Java领域优质创作者、CSDN博客专家、…

java 中 DTO 和 VO 的核心区别

DTO 和 VO 的核心区别 特性DTO&#xff08;数据传输对象&#xff09;VO&#xff08;视图对象&#xff09;设计目的服务层与外部系统&#xff08;如前端、其他服务&#xff09;之间的数据传输为前端展示层定制数据&#xff0c;通常与 UI 强绑定数据内容可能包含业务逻辑需要的字…

数据结构【二叉树的遍历实现】

&#x1f4d8;考研数据结构基础&#xff1a;二叉树的存储、遍历与队列辅助实现详 在数据结构的学习中&#xff0c;二叉树作为一种结构清晰、应用广泛的树形结构&#xff0c;是考研计算机专业课中重点内容之一。本文将以实际代码为基础&#xff0c;介绍二叉树的存储结构、遍历方…

无人机俯视风光摄影Lr调色预设,手机滤镜PS+Lightroom预设下载!

调色详情 无人机俯视风光摄影 Lr 调色是利用 Adobe Lightroom 软件&#xff0c;对无人机从俯视角度拍摄的风光照片进行后期处理的调色方式。通过调整色彩、对比度、光影等多种参数&#xff0c;能够充分挖掘并强化画面独特视角下的壮美与细节之美&#xff0c;让原本平凡的航拍风…

【springcloud学习(dalston.sr1)】Eureka服务端集群的搭建(含源代码)(二)

该系列项目整体介绍及源代码请参照前面写的一篇文章【springcloud学习(dalston.sr1)】项目整体介绍&#xff08;含源代码&#xff09;&#xff08;一&#xff09; 这篇文章主要介绍多个eureka服务端的集群环境是如何搭建的。 &#xff08;一&#xff09;eureka的简要说明 Eu…

互联网大厂Java求职面试实战:Spring Boot微服务与数据库优化详解

&#x1f4aa;&#x1f3fb; 1. Python基础专栏&#xff0c;基础知识一网打尽&#xff0c;9.9元买不了吃亏&#xff0c;买不了上当。 Python从入门到精通 &#x1f601; 2. 毕业设计专栏&#xff0c;毕业季咱们不慌忙&#xff0c;几百款毕业设计等你选。 ❤️ 3. Python爬虫专栏…

事件驱动reactor的原理与实现

fdset 集合&#xff1a;&#xff08;就是说&#xff09; fd_set是一个位图&#xff08;bitmap&#xff09;结构 每个位代表一个文件描述符 0表示不在集合中&#xff0c;1表示在集合中 fd_set结构&#xff08;简化&#xff09;&#xff1a; [0][1][2][3][4][5]...[1023] …