{"id":4423,"date":"2025-09-09T18:09:07","date_gmt":"2025-09-09T10:09:07","guid":{"rendered":"https:\/\/www.caiqinyi.cn\/?p=4423"},"modified":"2025-09-09T18:09:07","modified_gmt":"2025-09-09T10:09:07","slug":"ue5_design_pattern_visitor_pattern","status":"publish","type":"post","link":"https:\/\/www.caiqinyi.cn\/index.php\/2025\/09\/09\/ue5_design_pattern_visitor_pattern\/","title":{"rendered":"[UE5 \u8bbe\u8ba1\u6a21\u5f0f] \u8bbf\u95ee\u8005\u6a21\u5f0fVisitor Pattern"},"content":{"rendered":"<p><script type=\"text\/javascript\" async src=\"https:\/\/www.caiqinyi.cn\/wp-content\/MathJax\/MathJax.js?config=TeX-AMS_CHTML\">\n<\/script><br \/>\n<script type=\"text\/x-mathjax-config\">\n    MathJax.Hub.Config({\n        tex2jax: {inlineMath: [['$','$']]},\n        TeX: {equationNumbers: {autoNumber: [\"AMS\"], useLabelIds: true}},\n        \"HTML-CSS\": {linebreaks: {automatic: true}},\n        SVG: {linebreaks: {automatic: true}}\n    });\n<\/script><\/p>\n<p><strong>\u53c2\u8003\u6750\u6599<\/strong><br \/>\n1. <a href=\"https:\/\/www.cnblogs.com\/shiroe\/p\/14909707.html\">\u3010UE4 \u8bbe\u8ba1\u6a21\u5f0f\u3011\u7b56\u7565\u6a21\u5f0f Strategy Pattern<\/a><br \/>\n2. <a href=\"https:\/\/www.runoob.com\/design-pattern\/visitor-pattern.html\">\u8bbf\u95ee\u8005\u6a21\u5f0f<\/a><br \/>\n3. <a href=\"https:\/\/blog.csdn.net\/qq_33060405\/article\/details\/139455750\">\u6e38\u620f\u5f00\u53d1\uff1a\u8bbf\u95ee\u8005\u6a21\u5f0f\u5b9e\u6218\u89e3\u6790<\/a><\/p>\n<p><strong>1. \u6982\u8ff0<\/strong><\/p>\n<p><strong>1.1 \u63cf\u8ff0<\/strong><\/p>\n<p>$\\cdot$ \u5728\u8bbf\u95ee\u8005\u6a21\u5f0f(Visitor Pattern)\u4e2d, \u6211\u4eec\u4f7f\u7528\u4e86\u4e00\u4e2a\u8bbf\u95ee\u8005\u7c7b, \u5b83\u6539\u53d8\u4e86\u5143\u7d20\u7c7b\u7684\u6267\u884c\u7b97\u6cd5. \u901a\u8fc7\u8fd9\u79cd\u65b9\u5f0f, \u5143\u7d20\u7684\u6267\u884c\u7b97\u6cd5\u53ef\u4ee5\u968f\u7740\u8bbf\u95ee\u8005\u6539\u53d8\u800c\u6539\u53d8. \u8fd9\u79cd\u7c7b\u578b\u7684\u8bbe\u8ba1\u6a21\u5f0f\u5c5e\u4e8e\u884c\u4e3a\u578b\u6a21\u5f0f. \u6839\u636e\u6a21\u5f0f, \u5143\u7d20\u5bf9\u8c61\u5df2\u63a5\u53d7\u8bbf\u95ee\u8005\u5bf9\u8c61, \u8fd9\u6837\u8bbf\u95ee\u8005\u5bf9\u8c61\u5c31\u53ef\u4ee5\u5904\u7406\u5143\u7d20\u5bf9\u8c61\u4e0a\u7684\u64cd\u4f5c.<\/p>\n<p><!--more--><\/p>\n<p><strong>1.2 \u5957\u8def<\/strong><\/p>\n<p>$\\cdot$ <strong>\u5b9e\u73b0\u65b9\u5f0f:<\/strong><br \/>\n$\\\\$ 1) \u5b9a\u4e49\u8bbf\u95ee\u8005\u63a5\u53e3: \u58f0\u660e\u4e00\u7cfb\u5217\u8bbf\u95ee\u65b9\u6cd5, \u4e00\u4e2a\u8bbf\u95ee\u65b9\u6cd5\u5bf9\u5e94\u6570\u636e\u7ed3\u6784\u4e2d\u7684\u4e00\u4e2a\u5143\u7d20\u7c7b.<br \/>\n$\\\\$ 2) \u521b\u5efa\u5177\u4f53\u8bbf\u95ee\u8005: \u5b9e\u73b0\u8bbf\u95ee\u8005\u63a5\u53e3, \u4e3a\u6bcf\u4e2a\u8bbf\u95ee\u65b9\u6cd5\u63d0\u4f9b\u5177\u4f53\u5b9e\u73b0.<br \/>\n$\\\\$ 3) \u5b9a\u4e49\u5143\u7d20\u63a5\u53e3: \u58f0\u660e\u4e00\u4e2a\u63a5\u53d7\u8bbf\u95ee\u8005\u7684\u65b9\u6cd5.<br \/>\n$\\\\$ 4) \u521b\u5efa\u5177\u4f53\u5143\u7d20: \u5b9e\u73b0\u5143\u7d20\u63a5\u53e3, \u6bcf\u4e2a\u5177\u4f53\u5143\u7d20\u7c7b\u5bf9\u5e94\u6570\u636e\u7ed3\u6784\u4e2d\u7684\u4e00\u4e2a\u5177\u4f53\u5bf9\u8c61.<\/p>\n<p>$\\cdot$ <strong>\u5173\u952e\u4ee3\u7801:<\/strong><br \/>\n$\\\\$ 1) \u8bbf\u95ee\u8005\u63a5\u53e3: \u5305\u542b\u8bbf\u95ee\u4e0d\u540c\u5143\u7d20\u7684\u65b9\u6cd5.<br \/>\n$\\\\$ 2) \u5177\u4f53\u8bbf\u95ee\u8005: \u5b9e\u73b0\u4e86\u8bbf\u95ee\u8005\u63a5\u53e3, \u5305\u542b\u5bf9\u6bcf\u4e2a\u5143\u7d20\u7c7b\u7684\u8bbf\u95ee\u903b\u8f91.<br \/>\n$\\\\$ 3) \u5143\u7d20\u63a5\u53e3: \u5305\u542b\u4e00\u4e2a\u63a5\u53d7\u8bbf\u95ee\u8005\u7684\u65b9\u6cd5.<br \/>\n$\\\\$ 4) \u5177\u4f53\u5143\u7d20: \u5b9e\u73b0\u4e86\u5143\u7d20\u63a5\u53e3, \u63d0\u4f9b\u7ed9\u8bbf\u95ee\u8005\u8bbf\u95ee\u7684\u5165\u53e3.<\/p>\n<p>$\\cdot$ <strong>\u7ed3\u6784:<\/strong><br \/>\n$\\\\$ \u5305\u542b\u7684\u51e0\u4e2a\u4e3b\u8981\u89d2\u8272<br \/>\n$\\\\$ 1) \u8bbf\u95ee\u8005(Visitor): \u5b9a\u4e49\u4e86\u8bbf\u95ee\u5143\u7d20\u7684\u63a5\u53e3.<br \/>\n$\\\\$ 2) \u5177\u4f53\u8bbf\u95ee\u8005(Concrete Visitor): \u5b9e\u73b0\u8bbf\u95ee\u8005\u63a5\u53e3, \u63d0\u4f9b\u5bf9\u6bcf\u4e2a\u5177\u4f53\u5143\u7d20\u7c7b\u7684\u8bbf\u95ee\u548c\u76f8\u5e94\u64cd\u4f5c.<br \/>\n$\\\\$ 3) \u5143\u7d20(Element): \u5b9a\u4e49\u4e86\u4e00\u4e2a\u63a5\u53d7\u8bbf\u95ee\u8005\u7684\u65b9\u6cd5.<br \/>\n$\\\\$ 4) \u5177\u4f53\u5143\u7d20(Concrete Element): \u5b9e\u73b0\u5143\u7d20\u63a5\u53e3, \u63d0\u4f9b\u4e00\u4e2aAccept\u65b9\u6cd5, \u5141\u8bb8\u8bbf\u95ee\u8005\u8bbf\u95ee\u5e76\u64cd\u4f5c.<br \/>\n$\\\\$ 5) \u5bf9\u8c61\u7ed3\u6784(Object Structure)(\u53ef\u9009): \u5b9a\u4e49\u4e86\u5982\u4f55\u7ec4\u88c5\u5177\u4f53\u5143\u7d20, \u5982\u4e00\u4e2a\u7ec4\u5408\u7c7b.<br \/>\n$\\\\$ 6) \u5ba2\u6237\u7aef(Client)(\u53ef\u9009): \u4f7f\u7528\u8bbf\u95ee\u8005\u6a21\u5f0f\u5bf9\u5bf9\u8c61\u7ed3\u6784\u8fdb\u884c\u64cd\u4f5c.<\/p>\n<p><strong>1.3 \u4f7f\u7528\u573a\u666f<\/strong><\/p>\n<p>$\\cdot$ \u5f53\u9700\u8981\u5bf9\u4e00\u4e2a\u5bf9\u8c61\u7ed3\u6784\u4e2d\u7684\u5bf9\u8c61\u6267\u884c\u591a\u79cd\u4e0d\u540c\u7684\u4e14\u4e0d\u76f8\u5173\u7684\u64cd\u4f5c\u65f6, \u5c24\u5176\u662f\u8fd9\u4e9b\u64cd\u4f5c\u9700\u8981\u907f\u514d&#8221;\u6c61\u67d3&#8221; \u5bf9\u8c61\u7c7b\u672c\u8eab.<\/p>\n<p><strong>1.4 \u4f18\u7f3a\u70b9<\/strong><\/p>\n<p>$\\cdot$ <strong>\u4f18\u70b9:<\/strong><br \/>\n$\\\\$ 1) \u5355\u4e00\u804c\u8d23\u539f\u5219: \u8bbf\u95ee\u8005\u6a21\u5f0f\u7b26\u5408\u5355\u4e00\u804c\u8d23\u539f\u5219, \u6bcf\u4e2a\u7c7b\u53ea\u8d1f\u8d23\u4e00\u9879\u804c\u8d23.<br \/>\n$\\\\$ 2) \u6269\u5c55\u6027: \u5bb9\u6613\u4e3a\u6570\u636e\u7ed3\u6784\u6dfb\u52a0\u65b0\u7684\u64cd\u4f5c.<br \/>\n$\\\\$ 3) \u7075\u6d3b\u6027: \u8bbf\u95ee\u8005\u53ef\u4ee5\u72ec\u7acb\u4e8e\u6570\u636e\u7ed3\u6784\u53d8\u5316.<\/p>\n<p>$\\cdot$ <strong>\u7f3a\u70b9:<\/strong><br \/>\n$\\\\$ 1) \u8fdd\u53cd\u8fea\u7c73\u7279\u539f\u5219: \u5143\u7d20\u9700\u8981\u5411\u8bbf\u95ee\u8005\u516c\u5f00\u5176\u5185\u90e8\u4fe1\u606f.<br \/>\n$\\\\$ 2) \u5143\u7d20\u7c7b\u96be\u4ee5\u53d8\u66f4: \u5143\u7d20\u7c7b\u9700\u8981\u7ef4\u6301\u4e0e\u8bbf\u95ee\u8005\u7684\u517c\u5bb9.<br \/>\n$\\\\$ 3) \u4f9d\u8d56\u5177\u4f53\u7c7b: \u8bbf\u95ee\u8005\u6a21\u5f0f\u4f9d\u8d56\u4e8e\u5177\u4f53\u7c7b\u800c\u4e0d\u662f\u63a5\u53e3, \u8fdd\u53cd\u4e86\u4f9d\u8d56\u5012\u7f6e\u539f\u5219.<\/p>\n<p><strong>2. \u8bbf\u95ee\u8005\u6a21\u5f0f\u539f\u7406\u2014\u2014 \u751f\u52a8\u5f62\u8c61\u89e3\u91ca<\/strong><\/p>\n<p><strong>2.1 \u751f\u6d3b\u4e2d\u7684\u4f8b\u5b50<\/strong><\/p>\n<p>$\\cdot$ \u6bd4\u55bb: \u533b\u751f\u5de1\u8bca\u4e0d\u540c\u75c5\u4eba<br \/>\n$\\\\$ \u60f3\u8c61\u533b\u9662\u91cc\u6709\u5f88\u591a\u4e0d\u540c\u7c7b\u578b\u7684\u75c5\u4eba: \u5c0f\u5b69, \u6210\u5e74\u4eba, \u8001\u4eba.<br \/>\n$\\\\$ \u6bcf\u4e2a\u75c5\u4eba\u6709\u81ea\u5df1\u7684\u8eab\u4f53\u72b6\u51b5, \u4f46\u533b\u9662\u4f1a\u6709\u4e0d\u540c\u7684\u533b\u751f\u6765\u5de1\u8bca, \u6bd4\u5982\u5185\u79d1\u533b\u751f, \u5916\u79d1\u533b\u751f, \u5fc3\u7406\u533b\u751f.<br \/>\n$\\\\$ 1) \u75c5\u4eba\u7c7b(Element): \u5c0f\u5b69, \u6210\u5e74\u4eba, \u8001\u4eba.<br \/>\n$\\\\$ 2) \u533b\u751f\u7c7b(Visitor): \u5185\u79d1\u533b\u751f, \u5916\u79d1\u533b\u751f, \u5fc3\u7406\u533b\u751f.<br \/>\n$\\\\$ \u6bcf\u4e2a\u533b\u751f\u90fd\u80fd&#8221;\u8bbf\u95ee&#8221; \u6bcf\u4e2a\u75c5\u4eba, \u5e76\u6839\u636e\u75c5\u4eba\u7c7b\u578b\u505a\u4e0d\u540c\u7684\u68c0\u67e5\u548c\u5904\u7406.<\/p>\n<p>$\\cdot$ \u5173\u952e\u70b9: \u4f60\u4e0d\u7528\u5728\u75c5\u4eba\u7c7b\u91cc\u5199\u6240\u6709\u533b\u751f\u7684\u5904\u7406\u903b\u8f91, \u800c\u662f\u8ba9\u533b\u751f\u81ea\u5df1\u5e26\u7740&#8221;\u5904\u7406\u65b9\u6cd5&#8221; \u6765\u8bbf\u95ee\u75c5\u4eba.<\/p>\n<p>$\\cdot$ \u672c\u8d28: \u8bbf\u95ee\u8005\u6a21\u5f0f\u5c31\u662f\u628a\u5bf9\u4e00\u7ec4\u5bf9\u8c61\u7684\u64cd\u4f5c\u4ece\u5bf9\u8c61\u672c\u8eab\u5206\u79bb\u51fa\u6765, \u65b0\u589e\u64cd\u4f5c\u65f6\u4e0d\u7528\u4fee\u6539\u5bf9\u8c61\u7c7b, \u53ea\u9700\u589e\u52a0\u8bbf\u95ee\u8005\u7c7b.<\/p>\n<p><strong>2.2 \u6e38\u620f\u4e2d\u7684\u5b9e\u9645\u5e94\u7528<\/strong><\/p>\n<p>$\\cdot$ Buff\/\u72b6\u6001\u7cfb\u7edf: \u4e0d\u540cBuff(\u52a0\u8840, \u51cf\u901f, \u7729\u6655) \u8bbf\u95ee\u4e0d\u540c\u7c7b\u578b\u7684\u89d2\u8272(\u73a9\u5bb6, \u602a\u7269, NPC), \u5b9e\u73b0\u4e0d\u540c\u6548\u679c.<br \/>\n$\\\\$ $\\cdot$ \u6570\u636e\u5bfc\u51fa: \u5bfc\u51fa\u6e38\u620f\u4e2d\u5404\u79cd\u5bf9\u8c61(\u89d2\u8272, \u9053\u5177, \u5173\u5361) \u5230\u4e0d\u540c\u683c\u5f0f(JSON, XML, CSV).<br \/>\n$\\\\$ $\\cdot$ \u6280\u80fd\u7cfb\u7edf: \u6280\u80fd\u8bbf\u95ee\u4e0d\u540c\u76ee\u6807, \u4ea7\u751f\u4e0d\u540c\u6548\u679c.<\/p>\n<p><strong>3. UE5\u5b9e\u8df5(\u4ee5Buff\u7cfb\u7edf\u4e3a\u4f8b)<\/strong><\/p>\n<p><strong>3.1 \u5143\u7d20\u63a5\u53e3\u548c\u5177\u4f53\u5143\u7d20<\/strong><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"C++\" data-enlighter-theme=\"monokai\">\r\n\r\n#pragma once\r\n#include \"CoreMinimal.h\"\r\n\r\n\r\nclass IBuffVisitor;\r\n\r\n\/\/ \u5143\u7d20\u63a5\u53e3\r\nclass ICharacter\r\n{\r\npublic:\r\n\tvirtual void Accept(IBuffVisitor* Visitor) = 0;\r\n};\r\n\r\n\/\/ \u5177\u4f53\u5143\u7d20: \u73a9\u5bb6\r\nclass FPlayer : public ICharacter\r\n{\r\npublic:\r\n\tvirtual void Accept(IBuffVisitor* Visitor) override;\r\n\r\npublic:\r\n\tint32 HP = 100;\r\n};\r\n\r\n\/\/ \u5177\u4f53\u5143\u7d20: \u73a9\u5bb6\r\nclass FMonster : public ICharacter\r\n{\r\npublic:\r\n\tvirtual void Accept(IBuffVisitor* Visitor) override;\r\n\r\npublic:\r\n\tint32 HP = 50;\r\n};\r\n\r\n<\/pre>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"C++\" data-enlighter-theme=\"monokai\">\r\n\r\n#include \"Element.h\"\r\n\r\n\r\nvoid FPlayer::Accept(IBuffVisitor* Visitor)\r\n{\r\n\tVisitor.Visit(this);\r\n}\r\n\r\nvoid FMonster::Accept(IBuffVisitor* Visitor)\r\n{\r\n\tVisitor.Visit(this);\r\n}\r\n\r\n<\/pre>\n<p><strong>3.2 \u8bbf\u95ee\u8005\u63a5\u53e3\u548c\u5177\u4f53\u8bbf\u95ee\u8005<\/strong><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"C++\" data-enlighter-theme=\"monokai\">\r\n\r\n#pragma once\r\n\r\n\r\nclass FPlayer;\r\nclass FMonster;\r\n\r\n\/\/ \u8bbf\u95ee\u8005\u63a5\u53e3\r\nclass IBuffVisitor\r\n{\r\n\tvirtual void Visit(FPlayer* Player) = 0;\r\n\tvirtual void Visit(FMonster* Monster) = 0;\r\n};\r\n\r\n\/\/ \u5177\u4f53\u8bbf\u95ee\u8005: \u52a0\u8840Buff\r\nclass FHealBuff : public IBuffVisitor\r\n{\r\npublic:\r\n\tvirtual void Visit(FPlayer* Player) override;\r\n\tvirtual void Visit(FMonster* Monster) override;\r\n};\r\n\r\n\/\/ \u5177\u4f53\u8bbf\u95ee\u8005: \u4e2d\u6bd2Buff\r\nclass FPoisonBuff : public IBuffVisitor\r\n{\r\npublic:\r\n\tvirtual void Visit(FPlayer* Player) override;\r\n\tvirtual void Visit(FMonster* Monster) override;\r\n};\r\n\r\n<\/pre>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"C++\" data-enlighter-theme=\"monokai\">\r\n\r\n#include \"Visitor.h\"\r\n#include \"CoreMinimal.h\"\r\n\r\n\r\nvoid FHealBuff::Visit(FPlayer* Player)\r\n{\r\n\tPlayer->HP += 20;\r\n\tUE_LOG(LogTemp, Log, TEXT(\"\u73a9\u5bb6\u52a0\u8840\uff0c\u5f53\u524dHP\uff1a%d\"), Player->HP);\r\n}\r\n\r\nvoid FHealBuff::Visit(FMonster* Monster)\r\n{\r\n\tMonster->HP += 10;\r\n\tUE_LOG(LogTemp, Log, TEXT(\"\u602a\u7269\u52a0\u8840\uff0c\u5f53\u524dHP\uff1a%d\"), Monster->HP);\r\n}\r\n\r\nvoid FPoisonBuff::Visit(FPlayer* Player)\r\n{\r\n\tPlayer->HP -= 15;\r\n\tUE_LOG(LogTemp, Log, TEXT(\"\u73a9\u5bb6\u4e2d\u6bd2\uff0c\u5f53\u524dHP\uff1a%d\"), Player->HP);\r\n}\r\n\r\nvoid FPoisonBuff::Visit(FMonster* Monster)\r\n{\r\n\tMonster->HP -= 6;\r\n\tUE_LOG(LogTemp, Log, TEXT(\"\u602a\u7269\u4e2d\u6bd2\uff0c\u5f53\u524dHP\uff1a%d\"), Monster->HP);\r\n}\r\n\r\n<\/pre>\n<p><strong>3.3 \u4f7f\u7528\u793a\u4f8b<\/strong><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"C++\" data-enlighter-theme=\"monokai\">\r\n\r\n#include \"Element.h\"\r\n#include \"Visitor.h\"\r\n\r\n\r\nint main()\r\n{\r\n\tICharacter* Player = new FPlayer();\r\n\tICharacter* Monster = new FMonster();\r\n\r\n\tIBuffVisitor* Heal = new FHealBuff();\r\n\tIBuffVisitor* Poison = new FPoisonBuff();\r\n\r\n\t\/\/ \u7ed9\u73a9\u5bb6\u548c\u602a\u7269\u52a0\u8840\r\n\tPlayer->Accept(Heal); \/\/ \u73a9\u5bb6\u52a0\u8840, \u5f53\u524dHP: 120\r\n\tMonster->Accept(Heal); \/\/ \u602a\u7269\u52a0\u8840, \u5f53\u524dHP: 60\r\n\r\n\t\/\/ \u7ed9\u73a9\u5bb6\u548c\u602a\u7269\u4e2d\u6bd2\r\n\tPlayer->Accept(Poison); \/\/ \u73a9\u5bb6\u4e2d\u6bd2\uff0c\u5f53\u524dHP\uff1a105\r\n\tMonster->Accept(Poison); \/\/ \u602a\u7269\u4e2d\u6bd2\uff0c\u5f53\u524dHP\uff1a55\r\n\r\n\tdelete Player;\r\n\tPlayer = nullptr;\r\n\r\n\tdelete Monster;\r\n\tMonster = nullptr;\r\n\r\n\tdelete Heal;\r\n\tHeal = nullptr;\r\n\r\n\tdelete Poison;\r\n\tPoison = nullptr;\r\n\r\n\treturn 0;\r\n}\r\n\r\n<\/pre>\n<p><strong>3.4 \u53e3\u8bc0\u603b\u7ed3<\/strong><\/p>\n<blockquote>\n<p>\u8bbf\u95ee\u8005\u50cf\u533b\u751f,<br \/>\n\u5143\u7d20\u662f\u75c5\u4eba;<br \/>\n\u65b0\u589e\u64cd\u4f5c\u52a0\u533b\u751f,<br \/>\n\u75c5\u4eba\u4ee3\u7801\u4e0d\u7528\u53d8!<\/p>\n<\/blockquote>\n<p>\u6bd4\u5982\u4f60\u6709\u4e00\u7ec4\u573a\u666f\u5bf9\u8c61(NPC, \u602a\u7269, \u5b9d\u7bb1), \u4f60\u60f3\u5b9e\u73b0&#8221;\u5bfc\u51fa\u6570\u636e\u5230JSON&#8221; \u548c&#8221;\u5bfc\u51fa\u5230XML&#8221; \u4e24\u79cd\u64cd\u4f5c.<br \/>\n$\\\\$ \u7528\u8bbf\u95ee\u8005\u6a21\u5f0f, \u6bcf\u79cd\u5bfc\u51fa\u65b9\u5f0f\u5199\u4e00\u4e2a\u8bbf\u95ee\u8005, \u540e\u7eed\u8981\u52a0&#8221;\u5bfc\u51fa\u5230CSV&#8221; \u53ea\u9700\u52a0\u4e00\u4e2a\u8bbf\u95ee\u8005\u7c7b, \u539f\u6709\u5bf9\u8c61\u4e0d\u7528\u52a8.<\/p>\n<p><strong>4. \u6df1\u5165\u7406\u89e3<\/strong><\/p>\n<p>\u4e0b\u9762\u6211\u4eec\u5c06\u6df1\u5165\u7406\u89e3:<br \/>\n$\\\\$ 1) \u53cc\u5206\u6d3e\u539f\u7406(\u8bbf\u95ee\u8005\u6a21\u5f0f\u7684\u6838\u5fc3).<br \/>\n$\\\\$ 2) \u8bbf\u95ee\u8005\u94fe(Visitor Chain \/ Chain of Visitors).<br \/>\n$\\\\$ 3) \u590d\u6742\u6848\u4f8b(\u5982\u6280\u80fd\u7cfb\u7edf, \u5bfc\u51fa\u7cfb\u7edf\u7b49).<\/p>\n<p><strong>4.1 \u53cc\u5206\u6d3e\u539f\u7406(Double Dispatch)<\/strong><\/p>\n<p>1) \u5355\u5206\u6d3e vs \u53cc\u5206\u6d3e<br \/>\n$\\\\$ \u5355\u5206\u6d3e: C#, Java\u7b49\u8bed\u8a00\u9ed8\u8ba4\u662f&#8221;\u5355\u5206\u6d3e&#8221;, \u5373\u65b9\u6cd5\u8c03\u7528\u53ea\u6839\u636e\u63a5\u6536\u8005\u5bf9\u8c61\u7684\u5b9e\u9645\u7c7b\u578b\u51b3\u5b9a\u8c03\u7528\u54ea\u4e2a\u65b9\u6cd5.<br \/>\n$\\\\$ \u53cc\u5206\u6d3e: \u8bbf\u95ee\u8005\u6a21\u5f0f\u5b9e\u73b0\u4e86&#8221;\u6839\u636e\u8bbf\u95ee\u8005\u7c7b\u578b\u548c\u88ab\u8bbf\u95ee\u8005\u7c7b\u578b\u5171\u540c\u51b3\u5b9a\u8c03\u7528\u54ea\u4e2a\u65b9\u6cd5&#8221;.<\/p>\n<p>2) \u5f62\u8c61\u89e3\u91ca<br \/>\n$\\\\$ \u6bd4\u55bb: \u4f60(\u8bbf\u95ee\u8005) \u53bb\u533b\u9662(\u5143\u7d20), \u4f60\u662f\u5185\u79d1\u533b\u751f, \u75c5\u4eba\u662f\u5c0f\u5b69.<br \/>\n$\\\\$ $\\cdot$ \u533b\u9662\u5148\u770b\u4f60\u662f\u54ea\u4e2a\u533b\u751f(\u8bbf\u95ee\u8005\u7c7b\u578b),<br \/>\n$\\\\$ $\\cdot$ \u518d\u770b\u75c5\u4eba\u662f\u54ea\u4e2a\u7c7b\u578b(\u5143\u7d20\u7c7b\u578b),<br \/>\n$\\\\$ $\\cdot$ \u6700\u7ec8\u51b3\u5b9a\u8c03\u7528&#8221;\u5185\u79d1\u533b\u751f\u7ed9\u5c0f\u5b69\u770b\u75c5&#8221; \u7684\u65b9\u6cd5.<\/p>\n<p>3) \u4ee3\u7801\u6f14\u793a<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"C++\" data-enlighter-theme=\"monokai\">\r\n\r\n#pragma once\r\n#include \"CoreMinimal.h\"\r\n\r\n\r\n\/\/ \u5143\u7d20\u63a5\u53e3\r\nclass IElement\r\n{\r\npublic:\r\n\tvirtual void Accept(class IVisitor* Visitor) = 0;\r\n};\r\n\r\n\/\/ \u8bbf\u95ee\u8005\u63a5\u53e3\r\nclass IVisitor\r\n{\r\npublic:\r\n\tvirtual void Visit(class FElementA* A) = 0;\r\n\tvirtual void Visit(class FElementB* B) = 0;\r\n}\r\n\r\n\/\/ \u5177\u4f53\u5143\u7d20\r\nclass FElementA : public IElement\r\n{\r\npublic:\r\n\tvirtual void Accept(class IVisitor* Visitor) override\r\n\t{\r\n\t\tVisitor->Visit(this); \/\/ \u8fd9\u91cc\u7684this\u7c7b\u578b\u662fFElementA\r\n\t}\r\n};\r\n\r\nclass FElementB : public IElement\r\n{\r\npublic:\r\n\tvirtual void Accept(class IVisitor* Visitor) override\r\n\t{\r\n\t\tVisitor->Visit(this); \/\/ \u8fd9\u91cc\u7684this\u7c7b\u578b\u662fFElementB\r\n\t}\r\n};\r\n\r\n\/\/ \u5177\u4f53\u8bbf\u95ee\u8005\r\nclass FVisitor1 : pulic IVisitor\r\n{\r\npublic:\r\n\tvirtual void Visit(FElementA* A) override\r\n\t{\r\n\t\tUE_LOG(LogTemp, Log, TEXT(\"Visitor1\u8bbf\u95eeElementA\"));\r\n\t}\r\n\r\n\tvirtual void Visit(FElementB* B) override\r\n\t{\r\n\t\tUE_LOG(LogTemp, Log, TEXT(\"Visitor1\u8bbf\u95eeElementB\"));\r\n\t}\r\n};\r\n\r\n<\/pre>\n<p>\u53cc\u5206\u6d3e\u8fc7\u7a0b:<br \/>\n$\\\\$ $\\cdot$ Element.Accept(Visitor): \u5148\u6839\u636eElement\u7684\u5b9e\u9645\u7c7b\u578b(ElementA \/ ElementB) \u8c03\u7528\u5bf9\u5e94\u7684Accept.<br \/>\n$\\\\$ $\\cdot$ Visitor.Visit(this): \u518d\u6839\u636eVisitor\u7684\u5b9e\u9645\u7c7b\u578b\u548cthis\u7684\u7c7b\u578b, \u8c03\u7528\u6b63\u786e\u7684Visit\u91cd\u8f7d.<\/p>\n<p><strong>4.2 \u8bbf\u95ee\u8005\u94fe(Visitor Chain)<\/strong><\/p>\n<p><strong>4.2.1 \u6982\u5ff5<\/strong><\/p>\n<p>\u8bbf\u95ee\u8005\u94fe\u662f\u6307\u591a\u4e2a\u8bbf\u95ee\u8005\u4f9d\u6b21\u4f5c\u7528\u4e8e\u540c\u4e00\u7ec4\u5143\u7d20, \u7c7b\u4f3c\u8d23\u4efb\u94fe\u6a21\u5f0f, \u4f46\u6bcf\u4e2a\u8bbf\u95ee\u8005\u90fd\u80fd\u5904\u7406\u5143\u7d20.<\/p>\n<p><strong>4.2.2 \u5f62\u8c61\u89e3\u91ca<\/strong><\/p>\n<p>\u6bd4\u5982\u4f60\u6709\u4e00\u7ec4\u89d2\u8272, \u5148\u8ba9&#8221;\u52a0\u8840Buff&#8221; \u8bbf\u95ee\u4e00\u904d, \u518d\u8ba9&#8221;\u4e2d\u6bd2Buff&#8221; \u8bbf\u95ee\u4e00\u904d, \u89d2\u8272\u4f1a\u4f9d\u6b21\u53d7\u5230\u591a\u79cd\u6548\u679c.<\/p>\n<p><strong>4.2.3 \u4ee3\u7801\u5b9e\u73b0<\/strong><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"C++\" data-enlighter-theme=\"monokai\">\r\n\r\n#include \"Element.h\"\r\n#include \"Visitor.h\"\r\n\r\n\r\nint main()\r\n{\r\n\tTArray<IBuffVisitor*> Visitors = {new FHealBuff(), new FPoisonBuff()};\r\n\tTArray<ICharacter*> Elements = { new FPlayer(), new FMonster() };\r\n\r\n\tfor (auto& Visitor : Visitors)\r\n\t{\r\n\t\tfor (auto& Element : Elements)\r\n\t\t{\r\n\t\t\tElement->Accept(Visitor);\r\n\t\t}\r\n\t}\r\n\r\n\tfor (auto& Visitor : Visitors)\r\n\t{\r\n\t\tdelete Visitor;\r\n\t\tVisitor = nullptr;\r\n\t}\r\n\tVisitors.Empty();\r\n\r\n\tfor (auto& Element : Elements)\r\n\t{\r\n\t\tdelete Element;\r\n\t\tElement = nullptr;\r\n\t}\r\n\tElements.Empty();\r\n\r\n\treturn 0;\r\n}\r\n\r\n<\/pre>\n<p>\u8fd9\u6837\u6bcf\u4e2a\u89d2\u8272\u4f1a\u88ab\u6bcf\u4e2aBuff\u8bbf\u95ee\u4e00\u6b21.<\/p>\n<p><strong>4.3 UE\u590d\u6742\u6848\u4f8b<\/strong><\/p>\n<p><strong>4.3.1 \u6280\u80fd\u7cfb\u7edf\u4e2d\u7684\u8bbf\u95ee\u8005\u6a21\u5f0f<\/strong><\/p>\n<p>\u573a\u666f: \u4f60\u6709\u591a\u79cd\u6280\u80fd(\u706b\u7403, \u6cbb\u7597, \u51b0\u51bb), \u6bcf\u79cd\u6280\u80fd\u5bf9\u4e0d\u540c\u76ee\u6807(\u73a9\u5bb6, \u602a\u7269, \u5efa\u7b51) \u6709\u4e0d\u540c\u6548\u679c.<\/p>\n<p>\u4ee3\u7801\u7ed3\u6784<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"C++\" data-enlighter-theme=\"monokai\">\r\n\r\n#pragma once\r\n#include \"CoreMinimal.h\"\r\n\r\n\r\nclass ISkillVisitor;\r\n\r\n\/\/ \u76ee\u6807\u63a5\u53e3\r\nclass ITarget\r\n{\r\npublic:\r\n\tvirtual void Accept(ISkillVisitor* Visitor) = 0;\r\n};\r\n\r\n\/\/ \u5177\u4f53\u76ee\u6807\r\nclass FPlayer : public ITarget\r\n{\r\npublic:\r\n\tvirtual void Accept(ISkillVisitor* Visitor) override\r\n\t{\r\n\t\tVisitor->Visit(this);\r\n\t}\r\n\r\npublic:\r\n\tint32 HP = 100;\r\n};\r\n\r\nclass FMonster : public ITarget\r\n{\r\npublic:\r\n\tvirtual void Accept(ISkillVisitor* Visitor) override\r\n\t{\r\n\t\tVisitor->Visit(this);\r\n\t}\r\n\r\npublic:\r\n\tint32 HP = 50;\r\n};\r\n\r\nclass FBuilding : public ITarget\r\n{\r\npublic:\r\n\tvirtual void Accept(ISkillVisitor* Visitor) override\r\n\t{\r\n\t\tVisitor->Visit(this);\r\n\t}\r\n\r\npublic:\r\n\tint32 Durability = 200;\r\n};\r\n\r\n\/\/ \u6280\u80fd\u8bbf\u95ee\u8005\u63a5\u53e3\r\nclass ISkillVisitor\r\n{\r\npublic:\r\n\tvirtual void Visit(FPlayer* Player) = 0;\r\n\tvirtual void Visit(FMonster* Monster) = 0;\r\n\tvirtual void Visit(FBuilding* Building) = 0;\r\n};\r\n\r\n\/\/ \u5177\u4f53\u6280\u80fd\r\nclass FFireballSkill : public ISkillVisitor\r\n{\r\npublic:\r\n\tvirtual void Visit(FPlayer* Player) override\r\n\t{\r\n\t\tPlayer->HP -= 10;\r\n\t\tUE_LOG(LogTemp, Log, TEXT(\"\u73a9\u5bb6\u88ab\u706b\u7403\u51fb\u4e2d\uff0cHP: %d\"), Player->HP);\r\n\t}\r\n\r\n\tvirtual void Visit(FMonster* Monster) override\r\n\t{\r\n\t\tMonster->HP -= 30;\r\n\t\tUE_LOG(LogTemp, Log, TEXT(\"\u602a\u7269\u88ab\u706b\u7403\u51fb\u4e2d\uff0cHP: %d\"), Monster->HP);\r\n\t}\r\n\r\n\tvirtual void Visit(FBuilding* Building) override\r\n\t{\r\n\t\tBuilding->Durability -= 50;\r\n\t\tUE_LOG(LogTemp, Log, TEXT(\"\u5efa\u7b51\u88ab\u706b\u7403\u51fb\u4e2d\uff0c\u8010\u4e45: %d\"), Building->Durability);\r\n\t}\r\n};\r\n\r\nclass FHealSkill : public ISkillVisitor\r\n{\r\npublic:\r\n\tvirtual void Visit(FPlayer* Player) override\r\n\t{\r\n\t\tPlayer->HP += 20;\r\n\t\tUE_LOG(LogTemp, Log, TEXT(\"\u73a9\u5bb6\u88ab\u6cbb\u7597\uff0cHP: %d\"), Player->HP);\r\n\t}\r\n\r\n\tvirtual void Visit(FMonster* Monster) override\r\n\t{\r\n\t\t\/*\u602a\u7269\u4e0d\u80fd\u88ab\u6cbb\u7597*\/\r\n\t}\r\n\r\n\tvirtual void Visit(FBuilding* Building) override\r\n\t{\r\n\t\t\/*\u5efa\u7b51\u4e0d\u80fd\u88ab\u6cbb\u7597*\/\r\n\t}\r\n};\r\n\r\n<\/pre>\n<p>\u4f7f\u7528\u65b9\u5f0f<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"C++\" data-enlighter-theme=\"monokai\">\r\n\r\n#include \"TargetAndSkillVisitor.h\"\r\n\r\n\r\nint main()\r\n{\r\n\tTArray<ITarget*> Targets = { new FPlayer(), new FMonster(), new FBuilding() };\r\n\tISkillVisitor* Fireball = new FFireballSkill();\r\n\tISkillVisitor* Heal = new FHealSkill();\r\n\r\n\tfor (auto& Target : Targets)\r\n\t{\r\n\t\tTarget->Accept(Fireball); \/\/ \u6240\u6709\u76ee\u6807\u90fd\u88ab\u706b\u7403\u8bbf\u95ee\r\n\t\tTarget->Accept(Heal); \/\/ \u6240\u6709\u76ee\u6807\u90fd\u88ab\u6cbb\u7597\u8bbf\u95ee\r\n\t}\r\n\r\n\tfor (auto& Target : Targets)\r\n\t{\r\n\t\tdelete Target;\r\n\t\tTarget = nullptr;\r\n\t}\r\n\tTargets.Empty();\r\n\r\n\tdelete Fireball;\r\n\tFireball = nullptr;\r\n\r\n\tdelete Heal;\r\n\tHeal = nullptr;\r\n\r\n\treturn 0;\r\n}\r\n\r\n<\/pre>\n<p><strong>4.3.2 \u6e38\u620f\u5bf9\u8c61\u5bfc\u51fa\u7cfb\u7edf<\/strong><\/p>\n<p>\u573a\u666f: \u4f60\u6709\u4e00\u5806\u6e38\u620f\u5bf9\u8c61(\u89d2\u8272, \u9053\u5177, \u5173\u5361), \u9700\u8981\u5bfc\u51fa\u4e3a\u4e0d\u540c\u683c\u5f0f(JSON, XML, CSV).<\/p>\n<p>\u4ee3\u7801\u7ed3\u6784<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"C++\" data-enlighter-theme=\"monokai\">\r\n\r\n#pragma once\r\n#include \"CoreMinimal.h\"\r\n\r\n\r\nclass IExportVisitor;\r\n\r\nclass IGameElement\r\n{\r\npublic:\r\n\tvirtual void Accept(IExportVisitor* Visitor) = 0;\r\n};\r\n\r\nclass FCharacter : public ITarget\r\n{\r\npublic:\r\n\tvirtual void Accept(ISkillVisitor* Visitor) override\r\n\t{\r\n\t\tVisitor->Visit(this);\r\n\t}\r\n\r\npublic:\r\n\tFString Name = TEXT(\"Hero\");\r\n};\r\n\r\nclass FItem : public ITarget\r\n{\r\npublic:\r\n\tvirtual void Accept(ISkillVisitor* Visitor) override\r\n\t{\r\n\t\tVisitor->Visit(this);\r\n\t}\r\n\r\npublic:\r\n\tFString ItemName = TEXT(\"Sword\");\r\n};\r\n\r\nclass IExportVisitor\r\n{\r\npublic:\r\n\tvirtual void Visit(FCharacter* Character) = 0;\r\n\tvirtual void Visit(FItem* Item) = 0;\r\n};\r\n\r\nclass FJsonExportVisitor : public IExportVisitor\r\n{\r\npublic:\r\n\tvirtual void Visit(FCharacter* Character) override\r\n\t{\r\n\t\tUE_LOG(LogTemp, Log, TEXT(\"\u5bfc\u51fa\u89d2\u8272\u4e3aJSON: %s\"), *(Character->Name));\r\n\t}\r\n\r\n\tvirtual void Visit(FItem* Item) override\r\n\t{\r\n\t\tUE_LOG(LogTemp, Log, TEXT(\"\u5bfc\u51fa\u9053\u5177\u4e3aJSON: %s\"), *(Monster->ItemName));\r\n\t}\r\n};\r\n\r\nclass FXMLExportVisitor : public IExportVisitor\r\n{\r\npublic:\r\n\tvirtual void Visit(FCharacter* Character) override\r\n\t{\r\n\t\tUE_LOG(LogTemp, Log, TEXT(\"\u5bfc\u51fa\u89d2\u8272\u4e3aXML: %s\"), *(Character->Name));\r\n\t}\r\n\r\n\tvirtual void Visit(FItem* Item) override\r\n\t{\r\n\t\tUE_LOG(LogTemp, Log, TEXT(\"\u5bfc\u51fa\u9053\u5177\u4e3aXML: %s\"), *(Monster->ItemName));\r\n\t}\r\n};\r\n\r\n<\/pre>\n<p>\u4f7f\u7528\u65b9\u5f0f<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"C++\" data-enlighter-theme=\"monokai\">\r\n\r\n#include \"GameElementAndExportVisitor.h\"\r\n\r\n\r\nint main()\r\n{\r\n\tTArray<IGameElement*> Elements = { new FCharacter(), new FItem() };\r\n\tIExportVisitor* JsonVisitor = new FJsonExportVisitor();\r\n\tIExportVisitor* XMLVisitor = new FXMLExportVisitor();\r\n\r\n\tfor (auto& Element : Elements)\r\n\t{\r\n\t\tElement->Accept(JsonVisitor);\r\n\t\tElement->Accept(XMLVisitor);\r\n\t}\r\n\r\n\tfor (auto& Element : Elements)\r\n\t{\r\n\t\tdelete Element;\r\n\t\tElement = nullptr;\r\n\t}\r\n\tElements.Empty();\r\n\r\n\tdelete JsonVisitor;\r\n\tJsonVisitor = nullptr;\r\n\r\n\tdelete XMLVisitor;\r\n\tXMLVisitor = nullptr;\r\n\r\n\treturn 0;\r\n}\r\n\r\n<\/pre>\n<p><strong>4.3.3 \u603b\u7ed3\u53e3\u8bc0<\/strong><\/p>\n<blockquote>\n<p>\u53cc\u5206\u6d3e, \u7c7b\u578b\u53cc\u91cd\u5224,<br \/>\n\u8bbf\u95ee\u8005\u94fe, \u6279\u91cf\u5904\u7406\u5fd9.<br \/>\nUE\u6280\u80fd, \u5bfc\u51fa\u7686\u53ef\u7528,<br \/>\n\u65b0\u589e\u64cd\u4f5c\u4e0d\u52a8\u539f\u5bf9\u8c61!<\/p>\n<\/blockquote>\n","protected":false},"excerpt":{"rendered":"<p>\u53c2\u8003\u6750\u6599 1. \u3010UE4 \u8bbe\u8ba1\u6a21\u5f0f\u3011\u7b56\u7565\u6a21\u5f0f Strategy Pattern 2. \u8bbf\u95ee\u8005\u6a21\u5f0f 3. \u6e38\u620f\u5f00 &hellip; <a href=\"https:\/\/www.caiqinyi.cn\/index.php\/2025\/09\/09\/ue5_design_pattern_visitor_pattern\/\" class=\"more-link\">\u7ee7\u7eed\u9605\u8bfb<span class=\"screen-reader-text\">[UE5 \u8bbe\u8ba1\u6a21\u5f0f] \u8bbf\u95ee\u8005\u6a21\u5f0fVisitor Pattern<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[9,32],"tags":[],"_links":{"self":[{"href":"https:\/\/www.caiqinyi.cn\/index.php\/wp-json\/wp\/v2\/posts\/4423"}],"collection":[{"href":"https:\/\/www.caiqinyi.cn\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.caiqinyi.cn\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.caiqinyi.cn\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.caiqinyi.cn\/index.php\/wp-json\/wp\/v2\/comments?post=4423"}],"version-history":[{"count":15,"href":"https:\/\/www.caiqinyi.cn\/index.php\/wp-json\/wp\/v2\/posts\/4423\/revisions"}],"predecessor-version":[{"id":4439,"href":"https:\/\/www.caiqinyi.cn\/index.php\/wp-json\/wp\/v2\/posts\/4423\/revisions\/4439"}],"wp:attachment":[{"href":"https:\/\/www.caiqinyi.cn\/index.php\/wp-json\/wp\/v2\/media?parent=4423"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.caiqinyi.cn\/index.php\/wp-json\/wp\/v2\/categories?post=4423"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.caiqinyi.cn\/index.php\/wp-json\/wp\/v2\/tags?post=4423"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}