用23种设计模式打造一个cocos creator的游戏框架----(九)访问者模式
1、模式标准
模式名称:访问者模式
模式分类:行为型
模式意图:将数据操作与数据结构分离,使得在不修改数据结构的前提下,可以添加或改变对数据的操作。
结构图:

适用于:
-
当你需要对一个复杂对象结构执行一些操作,并且你希望实现这些操作与该对象结构的类无关时。访问者模式使得你可以在不修改现有类的情况下添加新的操作。
-
当你需要清洁并且有逻辑的方式来操作复杂的对象结构时。将相关的操作逻辑放在一个访问者类中,使得你可以将复杂的操作逻辑与数据结构的类分离。
-
当你需要在不同的类上执行类似的操作,而不希望污染这些类的接口时。访问者模式允许你在不影响其他类的情况下添加新的操作。
2、分析与设计
访问者模式,简单描述就是一个访问者访问了你,对你提了一些建议和操作。这里打个比方,比如本来你只会发1234567乐符发音,音乐老师访问者过来说,听他的指挥,你说好的(accept),之后你就听从音乐老师的指挥,哼出了一个曲调。老师一走,你就啥都不会了。
在游戏设计中,不确定其他人是如何用这个访问者模式的,但是我的第一感觉是是否能用在攻击上面,比如单位A对单位B发动了一个火球攻击,火球在遇到单位B时,对其产生了伤害。这个火球只是一个特效,火球的伤害就是伤害访问者。
来问一下GPT是如何说的
在游戏开发中,访问者模式可以被用于处理各种复杂的游戏逻辑,包括你所描述的攻击和属性修改的场景。让我们来看一下这种方式的一些可能优点和缺点。
优点:
分离游戏逻辑:访问者模式可以将攻击逻辑和单位属性的修改逻辑从实体类(如单位类)中分离出来,使得代码更易于理解和维护。
易于添加新的操作:如果你在未来需要添加新的攻击方式或者修改属性的方式,你可以通过添加新的访问者类来实现,而不需要修改现有的单位类。
缺点:
可能会破坏封装:访问者模式需要访问者类能够访问被访问元素的内部状态(在这个案例中是单位的属性),这可能会破坏被访问元素的封装。
可能导致代码更复杂:如果游戏的逻辑不是很复杂,使用访问者模式可能会使代码变得不必要的复杂。
总的来说,将一次攻击作为攻击访问者,然后在攻击访问者中计算对被攻击单位的属性的修改,是一种可行的方式。但是,是否应该使用这种方式,取决于你的具体需求,包括你的游戏的复杂性,你对易于理解和维护的需求,以及你对封装的考虑等。
会破坏封装?什么意思,继续问
“这句话有些不理解,“可能会破坏被访问元素的封装””
“封装”是面向对象编程中的一个重要概念,它指的是将对象的内部状态和实现细节隐藏起来,只暴露出一组公开的接口供外部使用。封装有助于保护对象的内部状态不被外部直接修改,也有助于减少代码之间的耦合,使得代码更易于理解和维护。
在访问者模式中,访问者类需要访问被访问元素的内部状态,以便执行一些操作。这就意味着被访问元素需要提供一些公开的接口来暴露其内部状态,这可能会破坏被访问元素的封装。具体来说,一些本应该是私有的数据或者实现细节可能会被暴露出来,这可能使得被访问元素变得更加脆弱,也可能使得代码更难以理解和维护。
例如,假设你有一个
Unit类,它有一些私有的属性,如health(生命值)和armor(护甲)。在一般情况下,你可能只会提供一些公开的方法来修改这些属性,如decreaseHealth和increaseArmor,而不会直接暴露这些属性。但是,如果你使用访问者模式,你可能需要提供一些公开的接口来让AttackVisitor能够直接访问和修改health和armor,这就破坏了Unit的封装。
你有什么好的建议吗?
对于这个问题,一种可能的解决方案是使用 "双重分派"(double dispatch)。在这种模式下,你可以在被访问者(如单位)中定义一个接受访问者的方法,并在这个方法中调用访问者的相应方法。这样,访问者可以在被访问者的上下文中执行操作,而不需要直接访问被访问者的内部状态。下面是一个简化的示例:
class Unit {constructor(health, armor) {this.health = health;this.armor = armor;}accept(visitor) {visitor.visitUnit(this);}decreaseHealth(amount) {this.health -= amount;}increaseArmor(amount) {this.armor += amount;}
}class AttackVisitor {constructor(damage) {this.damage = damage;}visitUnit(unit) {unit.decreaseHealth(this.damage);// 更复杂的攻击逻辑可以在这里添加}
}let unit = new Unit(100, 50);
let attackVisitor = new AttackVisitor(10);
unit.accept(attackVisitor);
在上面的代码中,
AttackVisitor可以通过调用visitUnit方法来修改Unit的状态,而不需要直接访问Unit的health和armor属性。这样,Unit的封装性就得到了保护。这种方法的一个缺点是,如果你有多种类型的单位,你可能需要在
AttackVisitor中为每种单位类型定义一个不同的visit方法。然而,这种问题可以通过使用一些设计模式,如"策略模式"或"组合模式",来解决。这种方法的一个优点是,你可以轻松地添加新的访问者,如
DefenseVisitor,而不需要修改Unit类。这是访问者模式的一个主要优点。
总得来说的是可行的方案。
意图:将数据操作(伤害操作)与数据结构(受攻击者)分离,使得在不修改数据结构(受攻击者)的前提下,可以添加或改变对数据的操作(伤害操作)。
3、开始打造

import { IUnitItem } from "../items/IItem"export interface IAttackVisitor {// 普通单位visitNormalUnitItem(unitItem: IUnitItem): void// 英雄单位visitHeroUnitItem(unitItem: IUnitItem): void
}
import { IUnitItem } from "../items/IItem";
import { IAttackVisitor } from "./IAttackVisitor";// 单体攻击
export class MonomerAttackVisitor implements IAttackVisitor {damage: number = 0constructor(damage: number) {this.damage = damage}// 普通单位visitUnitItem(unitItem: IUnitItem): void {unitItem.subHp(this.damage)}// 英雄单位,受到伤害值为0.8visitHeroUnitItem(unitItem: IUnitItem): void {unitItem.subHp(this.damage * 0.8)}
}
import { IUnitItem } from "../items/IItem";
import { IAttackVisitor } from "./IAttackVisitor";// 群体(衍射)攻击
export class GroupAttackVisitor implements IAttackVisitor {damage: number = 0constructor(damage: number) {this.damage = damage}// 普通单位visitUnitItem(unitItem: IUnitItem): void {unitItem.subHp(this.damage)// todo 周围单位也受到伤害}// 英雄单位,受到伤害值为0.8visitHeroUnitItem(unitItem: IUnitItem): void {unitItem.subHp(this.damage * 0.8)// todo 周围单位也受到伤害}
}
export interface IUnitItem {hp: numbersubHp(hp: number): voidaccept(visitor: IAttackVisitor): void
}
export class UnitItem extends Component implements IItem, IUnitItem {accept(visitor: IAttackVisitor) {visitor.visitUnitItem(this)}}
4、开始使用
export class UnitItem extends Component implements IItem, IUnitItem {ad: number = 100;accept(visitor: IAttackVisitor) {visitor.visitUnitItem(this)}attack(unitItem: UnitItem) {let damage = this.adlet attackVisitor = new MonomerAttackVisitor(damage)unitItem.accept(attackVisitor)}}
let unitItem001 = xhgame.itemFactory.createUnitItem('shibing_001')
let unitItem002 = xhgame.itemFactory.createUnitItem('shibing_002')unitItem001.attack(unitItem002)
有了访问者模式后,伤害管理变得更简单,目前只是简单版本,后续还得继续完善
相关文章:
用23种设计模式打造一个cocos creator的游戏框架----(九)访问者模式
1、模式标准 模式名称:访问者模式 模式分类:行为型 模式意图:将数据操作与数据结构分离,使得在不修改数据结构的前提下,可以添加或改变对数据的操作。 结构图: 适用于: 当你需要对一个复杂对…...
根文件系统初步测试
一. 简介 上一篇文章学习了向所编译生成的根文件系统中加入 lib库文件。文章地址如下: 根文件系统lib库添加与初步测试-CSDN博客 本文继上一篇文章的学习,本文对之前制作的根文件系统进行一次初步测试。 二. 根文件系统初步测试 为了方便测试&#…...
【精选】设计模式——策略设计模式-两种举例说明,具体代码实现
Java策略设计模式 简介 策略设计模式是一种行为型设计模式,它允许在运行时选择算法的行为。 在软件开发中,我们常常需要根据不同情况采取不同的行为。通常的做法是使用大量的条件语句来实现这种灵活性,但这会导致代码变得复杂、难以维护和扩…...
外包干了3个月,技术倒退2年。。。
先说情况,大专毕业,18年通过校招进入湖南某软件公司,干了接近6年的功能测试,今年年初,感觉自己不能够在这样下去了,长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了四年的功能测试…...
微信小程序:chooseimage从本地相册选择图片或使用相机拍照
文档 https://uniapp.dcloud.net.cn/api/media/image.html#chooseimage https://developers.weixin.qq.com/miniprogram/dev/api/media/image/wx.chooseImage.html 代码示例 const res await uni.chooseImage({count: 1, //默认9sizeType: [original, compressed], //可以…...
「Swift」取消UITableView起始位置在状态栏下方开始
前言:在写页面UI时发现,当隐藏了NavigationBar时,即使UITableView是从(0,0)进行布局,也会一直在手机状态栏下方进行展示布局,而我的想法是希望UITableView可以从状态栏处就进行展示布局 当前页面展示: 问题…...
android高版本适配使用Tools.java
随着android版本的提升,原生Tools不公开并且不能被正常使用,为了延续项目的功能,修改如下: /** Copyright (C) 2006 The Android Open Source Project** Licensed under the Apache License, Version 2.0 (the "License&quo…...
面试官:说说webpack中常见的Loader?解决了什么问题?
面试官:说说webpack中常见的Loader?解决了什么问题? 一、是什么 loader 用于对模块的"源代码"进行转换,在 import 或"加载"模块时预处理文件 webpack做的事情,仅仅是分析出各种模块的依赖关系&a…...
【蓝桥杯省赛真题50】Scratch智能计价器 蓝桥杯scratch图形化编程 中小学生蓝桥杯省赛真题讲解
目录 scratch智能计价器 一、题目要求 编程实现 二、案例分析 1、角色分析...
折半查找(数据结构实训)
题目: 标准输入输出 题目描述: 实现折半查找。要求查找给定的值在数据表中相应的存储位置。本题目假定输入元素均按非降序输入。 输入: 输入包含若干个测试用例,第一行为测试用例个数k。每个测试用例占3行,其中第一行为…...
AR助推制造业智能转型:实时远程协作与可视化引领生产创新
制造商面临着多方面的变革,技术的兴起催生了工业物联网(IIoT),改变了现代工厂的外貌、系统和流程。同时,全球竞争压力和不断变化的员工队伍要求采用新的员工培训方法,并重新审视工人在工厂中的角色。尽管如…...
【用unity实现100个游戏之18】从零开始制作一个类CSGO/CS2、CF第一人称FPS射击游戏——基础篇3(附项目源码)
文章目录 本节最终效果前言素材人物移动音效枪口火焰和开火音效枪口灯光弹孔和火花添加武器随镜头手臂摇摆效果源码完结 本节最终效果 前言 本节主要实现添加音效,和一些特效、武器摆动调整。 素材 素材,为了方便我直接用了unity免费的音效输出&#…...
sed 流式编辑器
使用方式: 1,前置指令 | sed 选项 定址符指令 2,sed 选项 定址符指令 被处理文档 选项: -n 屏蔽默认输出 -i写入文件 -r支持扩展正则 指令: p输出 d删除 s替换 sed -n 1p user //输出第1行 sed -n…...
Linux shell编程学习笔记33:type 命令
目录 0 引言1 type 命令的功能和格式 1.1 type命令的功能1.2 type 命令的格式2 type命令用法实例 2.1用type命令查看shell内置命令(以echo命令为例)2.2 用type命令查看别名(以ls命令为例)2.3 用type命令同时查看shell内置命令和别…...
【数据结构】—红黑树(C++实现)
🎬慕斯主页:修仙—别有洞天 💜本文前置知识: AVL树 ♈️今日夜电波:Letter Song—ヲタみん 1:36━━━━━━️💟──────── 5:35 …...
内衣洗衣机和手洗哪个干净?高性价比内衣洗衣机推荐
通常来说,我们的内衣裤对卫生要求比较高,毕竟是贴身穿的,所以如果和一般的衣物一起洗,就怕会有细菌互相感染。所以很多用户为了内衣裤的卫生都会选择自己手动洗,但手洗一方面很费时间和人力,另一方面又很伤…...
TikTok与互动广告:品牌如何打破传统界限
随着数字时代的蓬勃发展,广告行业也经历了翻天覆地的变革。在这个变革的浪潮中,TikTok作为一款崭新的社交媒体平台,通过其独特的短视频形式为品牌提供了全新的互动广告机会。 本文将深入探讨TikTok与互动广告的结合,以及品牌如何…...
跟着Nature Communications学习Hisat-Trinity-PASA等分析流程
一边学习,一边总结,一边分享! 详细教程请访问: 组学分析流程 本期分析流程 Hisat2-SamtoolsTrinity_GG_denovoPASA… 本期教程文章 题目:Genomic insights into local adaptation and future climate-induced vulnerability of a keystone forest tree in East Asia H…...
Unity中Batching优化的动态合批
文章目录 前言一、动态合批的规则1、材质相同是合批的前提,但是如果是材质实例的话,则一样无法合批。2、支持不同网格的合批3、动态合批需要网格支持的顶点条件二、我们导入一个模型并且制作一个Shader,来测试动态合批1、我们选择模型的 Mesh…...
2022年第十一届数学建模国际赛小美赛B题序列的遗传过程解题全过程文档及程序
2022年第十一届数学建模国际赛小美赛 B题 序列的遗传过程 原题再现: 序列同源性是指DNA、RNA或蛋白质序列之间的生物同源性,根据生命进化史中的共同祖先定义[1]。DNA、RNA或蛋白质之间的同源性通常根据它们的核苷酸或氨基酸序列相似性来推断。显著的相…...
ContextMenuManager:3分钟彻底清理Windows右键菜单的免费神器
ContextMenuManager:3分钟彻底清理Windows右键菜单的免费神器 【免费下载链接】ContextMenuManager 🖱️ 纯粹的Windows右键菜单管理程序 项目地址: https://gitcode.com/gh_mirrors/co/ContextMenuManager 你是否经常在Windows右键菜单中迷失方向…...
ContextMenuManager:5分钟掌握Windows右键菜单管理的终极免费方案
ContextMenuManager:5分钟掌握Windows右键菜单管理的终极免费方案 【免费下载链接】ContextMenuManager 🖱️ 纯粹的Windows右键菜单管理程序 项目地址: https://gitcode.com/gh_mirrors/co/ContextMenuManager 你是否厌倦了每次右键点击文件时&a…...
别再为调试发愁!FreeRTOS下STM32串口打印的三种实用方案(含USART3重定向避坑)
FreeRTOS下STM32串口调试的三大实战方案与深度优化指南 在嵌入式开发中,调试信息的输出如同黑夜中的灯塔,为开发者指明程序运行的轨迹。当FreeRTOS遇上STM32,串口打印这个看似基础的功能却可能成为项目推进的绊脚石。本文将带您深入探索三种经…...
从NeoPixel到CircuitPython:打造智能LED眼镜的完整硬件与软件实践
1. 项目概述 如果你对可穿戴电子设备、酷炫的LED光效以及用代码创造物理交互感兴趣,那么这个项目绝对能让你兴奋起来。今天要分享的,是如何亲手制作一副灵感来源于电子音乐人REZZ标志性风格的NeoPixel LED眼镜。这不仅仅是一个简单的焊接和组装教程&…...
DS18B20单总线温度传感器在CircuitPython中的实战应用指南
1. 项目概述与单总线协议的价值如果你正在用像Adafruit Feather M0 Express或Raspberry Pi Pico这类小巧的板子做项目,需要测量温度,DS18B20绝对是一个绕不开的经典选择。我这些年做过不少环境监测、智能家居的小玩意儿,从鱼缸水温到3D打印机…...
用于免训练手术视频分割的记忆增强SAM2(MA-SAM2)
学影像 手术视频 基础模型增强 ──────────────────────────────────────── 1. 标题 英文:Memory-Augmented SAM2 for Training-Free Surgical Video Segmentation 中文:用于免训练手术视频分割的记忆增强SAM2(MA-SAM2) 2. 作者…...
CodeWF Toolbox:一个用 Avalonia + Prism 做出来的开发者工具箱
今天这篇文章,站长来聊聊我自己开发的 CodeWF Toolbox,CodeWF 工具箱。熟悉我的朋友一般都叫我“站长”,因为我还有一个网站:CodeWF。这个工具箱也是围绕我平时写代码、维护网站、整理资料、排查问题时反复遇到的需求做出来的。它…...
从Launch/Capture路径理解CRPR:一个例子讲清楚它在Setup/Hold检查中的关键作用
从Launch/Capture路径理解CRPR:一个例子讲清楚它在Setup/Hold检查中的关键作用 在芯片后端设计中,时序分析是确保电路功能正确的关键环节。当我们谈论时钟路径分析时,CRPR(Clock Reconvergence Pessimism Removal)是一…...
PySOT单目标跟踪实战:从零搭建环境到模型部署的避坑指南(手把手教学,附代码)
1. 环境准备:从零搭建PySOT开发环境 第一次接触PySOT时,我花了整整两天时间折腾环境配置,踩遍了所有能踩的坑。为了让你们少走弯路,我把这些经验整理成可复现的步骤。首先需要明确的是,PySOT对系统环境有特定要求&…...
氯气,氯水,液溴,溴水,溴的四氯化碳溶液,碘单质,碘水的颜色分别是什么?
一、氯气(Cl₂)及其溶液物质颜色备注氯气(气体)黄绿色常温下为有刺激性气味的气体氯水(水溶液)淡黄绿色因溶解少量氯气分子(Cl₂)所致;久置后因生成HClO和HCl,…...
