游戏设计模式(GoF 23种)
GoF(Gang of Four)23种经典设计模式,结合 UE5/C++ 讲解。
每种模式包含:原理与用途 → 最简C++示例 → UE中的应用
一、创建型模式(Creational)
关注对象的创建方式,解耦创建逻辑与使用逻辑。
1. 单例 Singleton
原理与用途
保证一个类全局只有一个实例,并提供统一访问点。用于管理全局状态,如游戏配置、音频管理器。
最简C++示例
class AudioManager
{
public:
static AudioManager& Get()
{
static AudioManager Instance;
return Instance;
}
void PlaySound(const std::string& Name) {}
private:
AudioManager() = default;
AudioManager(const AudioManager&) = delete;
};
// 使用
AudioManager::Get().PlaySound("Explosion");
UE中的应用
UE 不推荐裸单例,而是用 Subsystem 替代:
UGameInstanceSubsystem:生命周期与 GameInstance 绑定,整局游戏唯一UWorldSubsystem:生命周期与 World 绑定UEngineSubsystem:编辑器/引擎级别唯一
// 获取
UMySubsystem* Sub = GetGameInstance()->GetSubsystem<UMySubsystem>();
2. 工厂方法 Factory Method
原理与用途
定义创建对象的接口,让子类决定实例化哪个类。用于框架不知道需要创建哪种具体产品时。
最简C++示例
class Weapon { public: virtual void Fire() = 0; };
class Rifle : public Weapon { public: void Fire() override {} };
class Pistol : public Weapon { public: void Fire() override {} };
class WeaponFactory
{
public:
virtual Weapon* Create() = 0; // 工厂方法
};
class RifleFactory : public WeaponFactory
{
public:
Weapon* Create() override { return new Rifle(); }
};
UE中的应用
SpawnActor<T>()是最常用的工厂方法,通过TSubclassOf<T>在运行时决定生成哪个子类- 蓝图子类配合
TSubclassOf属性,让设计师指定具体类型
UPROPERTY(EditAnywhere)
TSubclassOf<AWeapon> WeaponClass;
AWeapon* Weapon = World->SpawnActor<AWeapon>(WeaponClass, SpawnTransform);
3. 抽象工厂 Abstract Factory
原理与用途
创建一系列相关对象的接口,不指定具体类。用于需要保证一组对象相互兼容时(如不同风格的UI套件)。
最简C++示例
// 抽象产品
class Button { public: virtual void Click() = 0; };
class Icon { public: virtual void Draw() = 0; };
// 抽象工厂
class UIFactory
{
public:
virtual Button* CreateButton() = 0;
virtual Icon* CreateIcon() = 0;
};
// 具体工厂(科幻风格)
class ScifiUIFactory : public UIFactory
{
public:
Button* CreateButton() override { return new ScifiButton(); }
Icon* CreateIcon() override { return new ScifiIcon(); }
};
UE中的应用
- 用
UDataAsset定义一套主题配置,工厂读取 DataAsset 生成对应对象 - 不同平台(PC/Mobile)生成不同 UI 控件集合
UUserWidget的工厂创建:CreateWidget<UMyWidget>()
4. 建造者 Builder
原理与用途
将复杂对象的构建过程分步进行,同样的构建过程可以产生不同结果。用于构建参数很多、步骤复杂的对象。
最简C++示例
struct CharacterConfig { std::string Name; int HP; int ATK; };
class CharacterBuilder
{
CharacterConfig Config;
public:
CharacterBuilder& SetName(const std::string& Name) { Config.Name = Name; return *this; }
CharacterBuilder& SetHP(int HP) { Config.HP = HP; return *this; }
CharacterBuilder& SetATK(int ATK) { Config.ATK = ATK; return *this; }
CharacterConfig Build() { return Config; }
};
// 使用(链式调用)
auto Config = CharacterBuilder().SetName("Hero").SetHP(100).SetATK(50).Build();
UE中的应用
FActorSpawnParameters就是建造者思想:先配置各种参数,再传给SpawnActor- 编辑器中的
FPropertyChangedEvent构建流程 - 程序化生成关卡时,分步设置房间参数再生成
FActorSpawnParameters Params;
Params.Owner = this;
Params.Instigator = GetInstigator();
Params.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
World->SpawnActor<AEnemy>(EnemyClass, Transform, Params);
5. 原型 Prototype
原理与用途
通过克隆现有对象来创建新对象,避免重复初始化开销。用于创建与已有对象类似的对象时。
最简C++示例
class Monster
{
public:
int HP; std::string Name;
virtual Monster* Clone() { return new Monster(*this); } // 克隆自身
};
class BossMonster : public Monster
{
public:
Monster* Clone() override { return new BossMonster(*this); }
};
// 使用:从原型克隆
Monster* Prototype = new BossMonster();
Monster* Clone1 = Prototype->Clone();
Monster* Clone2 = Prototype->Clone();
UE中的应用
StaticDuplicateObject()/ 编辑器中的 Duplicate Actor(Ctrl+W)UObject::StaticDuplicateObject(Source, Outer)深拷贝 UObject- 关卡中批量放置同类 Actor 的基础机制
UObject* NewObj = StaticDuplicateObject(SourceObject, Outer, NAME_None);
二、结构型模式(Structural)
关注类和对象的组合方式,构建更大的结构。
6. 适配器 Adapter
原理与用途
将一个类的接口转换成客户期望的另一个接口,使原本不兼容的类可以合作。用于集成第三方库或遗留代码。
最简C++示例
// 旧接口
class OldLogger { public: void WriteLog(std::string Msg) {} };
// 目标接口
class ILogger { public: virtual void Log(std::string Msg) = 0; };
// 适配器
class LoggerAdapter : public ILogger
{
OldLogger Old;
public:
void Log(std::string Msg) override { Old.WriteLog(Msg); } // 转换调用
};
UE中的应用
UInterface是UE中适配器模式的核心工具:让不同类型的 Actor 暴露统一接口IAbilitySystemInterface让任意 Actor 提供 ASC,无需关心具体类型- 集成第三方物理/音频 SDK 时,用 Wrapper 类适配 UE 的调用约定
// 任何实现了接口的Actor都可以统一处理
if (IInteractable* Interactable = Cast<IInteractable>(HitActor))
{
Interactable->Interact(this);
}
7. 桥接 Bridge
原理与用途
将抽象与实现分离,使二者可以独立变化。用于避免“类爆炸“——当有多个维度的变化时。
classDiagram
class Shape {
-Renderer: IRenderer
+Render()*
}
class Circle {
+Render()
}
class IRenderer {
+Draw(string)*
}
class DX12Renderer {
+Draw(string)
}
class VulkanRenderer {
+Draw(string)
}
Shape <|-- Circle
Shape o-- IRenderer : bridge
IRenderer <|-- DX12Renderer
IRenderer <|-- VulkanRenderer
最简C++示例
// 实现层
class IRenderer { public: virtual void Draw(std::string Shape) = 0; };
class DX12Renderer : public IRenderer { public: void Draw(std::string Shape) override {} };
class VulkanRenderer : public IRenderer { public: void Draw(std::string Shape) override {} };
// 抽象层(持有实现的引用)
class Shape
{
protected:
IRenderer* Renderer;
public:
Shape(IRenderer* R) : Renderer(R) {}
virtual void Render() = 0;
};
class Circle : public Shape
{
public:
void Render() override { Renderer->Draw("Circle"); }
};
UE中的应用
- **RHI(Rendering Hardware Interface)**是桥接模式的典型:上层渲染逻辑不关心底层是 DX12 还是 Vulkan
FRHICommandList作为抽象层,后端实现可以是不同图形API- 音频系统:
UAudioComponent(抽象)与底层FAudioDevice(实现)分离
8. 组合 Composite
原理与用途
将对象组织成树形结构,使客户对单个对象和组合对象的使用方式一致。用于表示“部分-整体“层次结构。
classDiagram
class UIElement {
+Render()*
+Add(UIElement)
}
class Button {
+Render()
}
class Panel {
+Render()
+Add(UIElement)
}
UIElement <|-- Button
UIElement <|-- Panel
Panel o-- UIElement : children
最简C++示例
class UIElement
{
public:
virtual void Render() = 0;
virtual void Add(UIElement* E) {}
};
class Button : public UIElement // 叶节点
{
public:
void Render() override { /* 画按钮 */ }
};
class Panel : public UIElement // 容器节点
{
std::vector<UIElement*> Children;
public:
void Add(UIElement* E) override { Children.push_back(E); }
void Render() override { for (auto* C : Children) C->Render(); }
};
UE中的应用
USceneComponent树形层级:父子组件形成树,变换自动传递- UMG Widget 树:
UPanelWidget可以包含任意子 Widget,统一调用AddToViewport AActor的组件系统本身就是组合模式的体现
// SceneComponent 树
RootComponent → MeshComponent
→ WeaponComponent → MuzzleComponent
9. 装饰器 Decorator
原理与用途
动态地给对象添加职责,比继承更灵活。用于需要在运行时给对象增删功能时。
classDiagram
class IWeapon {
+GetDamage()*
}
class BaseGun {
+GetDamage()
}
class SilencerDecorator {
-Wrapped: IWeapon
+GetDamage()
}
IWeapon <|-- BaseGun
IWeapon <|-- SilencerDecorator
SilencerDecorator o-- IWeapon : wraps
最简C++示例
class IWeapon { public: virtual int GetDamage() = 0; };
class BaseGun : public IWeapon { public: int GetDamage() override { return 10; } };
// 装饰器:包装原对象,增加功能
class SilencerDecorator : public IWeapon
{
IWeapon* Wrapped;
public:
SilencerDecorator(IWeapon* W) : Wrapped(W) {}
int GetDamage() override { return Wrapped->GetDamage() - 2; } // 修改行为
};
// 使用
IWeapon* Gun = new SilencerDecorator(new BaseGun()); // 伤害 = 8
UE中的应用
- 动态挂载
UActorComponent是UE最自然的装饰器:运行时AddComponentByClass()给Actor追加能力 GameplayEffect叠层:对角色属性动态叠加/移除效果UActorComponent的bAutoActivate控制装饰是否生效
// 运行时给Actor动态添加功能组件
UMyBurningComponent* Comp = Cast<UMyBurningComponent>(
Actor->AddComponentByClass(UMyBurningComponent::StaticClass(), true, FTransform(), false)
);
10. 外观 Facade
原理与用途
为复杂子系统提供统一的简化接口。用于降低客户与子系统的耦合,提供易用的API层。
最简C++示例
// 复杂子系统
class PhysicsEngine { public: void Init() {} void Step(float Dt) {} };
class AudioEngine { public: void Init() {} void Play(std::string S) {} };
class NetworkManager { public: void Connect(std::string IP) {} };
// 外观:一个简单入口
class GameFacade
{
PhysicsEngine Physics;
AudioEngine Audio;
NetworkManager Network;
public:
void StartGame(std::string ServerIP)
{
Physics.Init();
Audio.Init();
Network.Connect(ServerIP);
}
};
UE中的应用
UGameplayStatics是最典型的外观:PlaySound2D、SpawnEmitterAtLocation等封装了复杂的子系统调用UKismetMathLibrary、UKismetSystemLibrary同理GetGameMode()、GetPlayerController()等全局访问函数也是外观思想
// 一行调用,隐藏内部复杂性
UGameplayStatics::PlaySoundAtLocation(this, ExplosionSound, GetActorLocation());
UGameplayStatics::SpawnEmitterAtLocation(World, FireFX, Transform);
11. 享元 Flyweight
原理与用途
通过共享来支持大量细粒度对象,将对象状态分为内部状态(共享)和外部状态(独有)。用于大量相似对象造成内存压力时。
最简C++示例
// 内部状态(共享)
class BulletData { public: std::string MeshPath; float Speed; };
// 享元工厂:相同类型只创建一次
class BulletFactory
{
std::unordered_map<std::string, BulletData*> Cache;
public:
BulletData* Get(const std::string& Type)
{
if (!Cache.count(Type)) Cache[Type] = new BulletData();
return Cache[Type];
}
};
// 外部状态(每颗子弹独有)
struct Bullet { BulletData* Data; FVector Position; FVector Velocity; };
UE中的应用
UStaticMesh共享:场景中1000棵树共享同一个UStaticMesh资源,只有 Transform 不同FName:UE内部对字符串做了享元处理,相同字符串只存一份UMaterialInstanceDynamic共享基础材质,只改动各自的参数HISM (Hierarchical Instanced Static Mesh)是享元+GPU实例化的结合
12. 代理 Proxy
原理与用途
为对象提供代理以控制对它的访问,可以延迟加载、访问控制、远程访问等。
最简C++示例
class ITexture { public: virtual void Render() = 0; };
class RealTexture : public ITexture
{
public:
RealTexture() { /* 加载耗时操作 */ }
void Render() override {}
};
// 代理:延迟到真正需要时才加载
class TextureProxy : public ITexture
{
RealTexture* Real = nullptr;
public:
void Render() override
{
if (!Real) Real = new RealTexture(); // 懒加载
Real->Render();
}
};
UE中的应用
TSoftObjectPtr<T>/TSoftClassPtr<T>:资源代理,不立即加载,需要时才LoadSynchronous()或异步加载- 网络 RPC:客户端调用看似本地函数,实际由代理发送到服务器执行
UChildActorComponent:代理管理子 Actor 的生命周期
// 软引用:代理模式
UPROPERTY(EditAnywhere)
TSoftObjectPtr<UTexture2D> LazyTexture;
// 需要时才真正加载
UTexture2D* Tex = LazyTexture.LoadSynchronous();
三、行为型模式(Behavioral)
关注对象之间的通信与职责分配。
13. 责任链 Chain of Responsibility
原理与用途
将请求沿链传递,直到有对象处理它。用于解耦请求发送者和接收者,支持多级处理。
classDiagram
class Handler {
-Next: Handler
+SetNext(Handler)
+Handle(int)
}
class LowHandler {
+Handle(int)
}
class HighHandler {
+Handle(int)
}
Handler <|-- LowHandler
Handler <|-- HighHandler
Handler o-- Handler : next
最简C++示例
class Handler
{
protected:
Handler* Next = nullptr;
public:
void SetNext(Handler* H) { Next = H; }
virtual void Handle(int Request)
{
if (Next) Next->Handle(Request); // 传递给下一个
}
};
class LowHandler : public Handler
{
public:
void Handle(int Request) override
{
if (Request < 10) { /* 处理 */ }
else Handler::Handle(Request); // 传递
}
};
UE中的应用
Enhanced Input的优先级映射:IMC按优先级叠加,高优先级先处理输入- UMG 的事件冒泡:子 Widget 未处理的输入事件向父级传递
APlayerController→APawn→ACharacter的输入处理链
14. 命令 Command
原理与用途
将操作封装为对象,支持撤销/重做、队列、日志记录。用于输入系统、操作历史、网络指令。
classDiagram
class ICommand {
+Execute()*
+Undo()*
}
class MoveCommand {
-Actor
-Delta: FVector
+Execute()
+Undo()
}
class Invoker {
-History: stack
+Do(ICommand)
+Undo()
}
ICommand <|-- MoveCommand
Invoker o-- ICommand : history
最简C++示例
class ICommand
{
public:
virtual void Execute() = 0;
virtual void Undo() = 0;
};
class MoveCommand : public ICommand
{
AActor* Actor; FVector Delta;
public:
MoveCommand(AActor* A, FVector D) : Actor(A), Delta(D) {}
void Execute() override { Actor->AddActorWorldOffset(Delta); }
void Undo() override { Actor->AddActorWorldOffset(-Delta); }
};
// 撤销栈
std::stack<ICommand*> History;
void Do(ICommand* Cmd) { Cmd->Execute(); History.push(Cmd); }
void Undo() { History.top()->Undo(); History.pop(); }
UE中的应用
UGameplayAbility:每个技能是一个命令对象,有ActivateAbility/EndAbilityUInputAction绑定:将输入事件映射为命令- 编辑器的 Undo/Redo 系统(
GEditor->UndoTransaction())就是命令模式
15. 迭代器 Iterator
原理与用途
提供顺序访问集合的方式,不暴露集合的内部结构。用于统一遍历不同类型的容器。
最简C++示例
class NumberList
{
std::vector<int> Data = {1, 2, 3, 4, 5};
public:
// 提供标准迭代器接口
auto begin() { return Data.begin(); }
auto end() { return Data.end(); }
};
// 使用:不关心内部是 vector 还是其他
NumberList List;
for (int Num : List) { /* 处理 */ }
UE中的应用
TArray/TMap的 range-for:for (AActor* Actor : Actors)TActorIterator<T>:遍历世界中所有某类型的 Actor
// 遍历世界中所有Enemy
for (TActorIterator<AEnemy> It(GetWorld()); It; ++It)
{
It->TakeDamage(10.f);
}
16. 中介者 Mediator
原理与用途
用中介对象封装一系列对象的交互,对象之间不直接引用彼此。用于减少多个对象之间的耦合。
最简C++示例
class Mediator; // 前向声明
class Player
{
Mediator* Med;
public:
Player(Mediator* M) : Med(M) {}
void SendMessage(std::string Msg);
void ReceiveMessage(std::string Msg) {}
};
class Mediator
{
std::vector<Player*> Players;
public:
void AddPlayer(Player* P) { Players.push_back(P); }
void Broadcast(std::string Msg, Player* Sender)
{
for (auto* P : Players)
if (P != Sender) P->ReceiveMessage(Msg);
}
};
UE中的应用
AGameMode:协调玩家、规则、生成等,各系统不直接通信AGameState:广播同步状态给所有客户端UEventSubsystem(自定义事件总线):解耦模块间通信
17. 备忘录 Memento
原理与用途
在不破坏封装的前提下,捕获并恢复对象的内部状态。用于存档、撤销、快照功能。
最简C++示例
// 备忘录:保存状态
struct Memento { int HP; FVector Position; };
class Character
{
int HP = 100; FVector Position;
public:
Memento Save() { return {HP, Position}; } // 存档
void Restore(Memento M) { HP = M.HP; Position = M.Position; } // 读档
};
// 存档管理器
std::stack<Memento> SaveSlots;
UE中的应用
USaveGame:UE 的存档系统,UGameplayStatics::SaveGameToSlot/LoadGameFromSlot- 编辑器中 Actor 属性的 Undo 记录(
FTransaction)
UCLASS()
class UMySaveGame : public USaveGame
{
GENERATED_BODY()
public:
UPROPERTY() int32 PlayerHP;
UPROPERTY() FVector PlayerPosition;
};
// 保存
UGameplayStatics::SaveGameToSlot(SaveGameObject, "Slot1", 0);
// 读取
USaveGame* Loaded = UGameplayStatics::LoadGameFromSlot("Slot1", 0);
18. 观察者 Observer
原理与用途
定义一对多依赖,当对象状态变化时自动通知所有依赖者。用于事件系统、UI数据绑定、解耦通知逻辑。
classDiagram
class Subject {
-Observers: list
+Subscribe(IObserver)
+SetValue(int)
}
class IObserver {
+OnNotify(int)*
}
class HUDWidget {
+OnNotify(int)
}
class SoundPlayer {
+OnNotify(int)
}
Subject o-- IObserver : 1..n
IObserver <|-- HUDWidget
IObserver <|-- SoundPlayer
最简C++示例
class IObserver { public: virtual void OnNotify(int Value) = 0; };
class Subject
{
std::vector<IObserver*> Observers;
int Value = 0;
public:
void Subscribe(IObserver* O) { Observers.push_back(O); }
void SetValue(int V)
{
Value = V;
for (auto* O : Observers) O->OnNotify(V); // 通知所有观察者
}
};
UE中的应用
DECLARE_MULTICAST_DELEGATE:UE 观察者的标准实现,类型安全,自动管理绑定
DECLARE_MULTICAST_DELEGATE_OneParam(FOnHealthChanged, float);
// 发布
FOnHealthChanged OnHealthChanged;
OnHealthChanged.Broadcast(NewHealth);
// 订阅
Character->OnHealthChanged.AddUObject(this, &UHUDWidget::UpdateHP);
// 取消订阅(销毁时)
Character->OnHealthChanged.RemoveAll(this);
GameplayTag事件:GetGameplayTagsComponent()->RegisterGameplayTagEvent()
19. 状态 State
原理与用途
允许对象在内部状态改变时改变行为,消除大量 if/switch。用于角色状态机、AI状态、游戏流程控制。
classDiagram
class Character {
-CurrentState: IState
+SetState(IState)
+Update(float)
}
class IState {
+Update(float)*
}
class IdleState {
+Update(float)
}
class AttackState {
+Update(float)
}
class DeadState {
+Update(float)
}
Character o-- IState : current
IState <|-- IdleState
IState <|-- AttackState
IState <|-- DeadState
最简C++示例
class IState { public: virtual void Update(float Dt) = 0; };
class IdleState : public IState
{
public:
void Update(float Dt) override { /* 播放待机动画 */ }
};
class AttackState : public IState
{
public:
void Update(float Dt) override { /* 执行攻击逻辑 */ }
};
class Character
{
IState* CurrentState = new IdleState();
public:
void SetState(IState* NewState) { CurrentState = NewState; }
void Update(float Dt) { CurrentState->Update(Dt); }
};
UE中的应用
- 动画蓝图状态机:最直观的状态模式应用,Idle → Run → Jump → Fall
- GAS
GameplayTag+AbilityTask:Tag 标记当前状态,Ability 是状态的行为 - AI
BehaviorTree的选择器/序列节点也体现状态切换逻辑
20. 策略 Strategy
原理与用途
定义一系列算法,使它们可以互相替换。用于运行时切换算法,如AI决策、寻路方式、伤害计算。
最简C++示例
class IMovementStrategy { public: virtual void Move(AActor* Actor) = 0; };
class WalkStrategy : public IMovementStrategy { public: void Move(AActor* A) override {} };
class FlyStrategy : public IMovementStrategy { public: void Move(AActor* A) override {} };
class Character
{
IMovementStrategy* Strategy = new WalkStrategy();
public:
void SetStrategy(IMovementStrategy* S) { Strategy = S; }
void Update(float Dt) { Strategy->Move(this); }
};
// 运行时切换
Character.SetStrategy(new FlyStrategy());
UE中的应用
UCharacterMovementComponent可以替换为自定义移动组件,切换不同移动策略UBTTask(行为树任务):不同 AI 使用不同 Task 组合,实现不同决策策略UGameplayAbility的不同技能作为战斗策略互相替换
21. 模板方法 Template Method
原理与用途
在父类定义算法骨架,将某些步骤的实现延迟到子类。用于框架定义流程,子类定制细节。
最简C++示例
class Game
{
public:
// 模板方法:固定流程
void Run()
{
Initialize(); // 子类实现
while (!IsOver()) Update();
Shutdown();
}
protected:
virtual void Initialize() = 0;
virtual void Update() = 0;
virtual bool IsOver() = 0;
virtual void Shutdown() {}
};
class MyGame : public Game
{
void Initialize() override { /* 加载资源 */ }
void Update() override { /* 游戏逻辑 */ }
bool IsOver() override { return false; }
};
UE中的应用
AActor生命周期虚函数是模板方法的典型:BeginPlay/Tick/EndPlay,引擎定义调用时机,游戏代码实现具体行为AGameMode的InitGame/PostLogin/HandleMatchHasEnded等回调UUserWidget的NativeConstruct/NativeTick/NativeDestruct
22. 访问者 Visitor
原理与用途
在不改变类的前提下为其增加新操作。用于对一个对象结构中的元素执行多种不同操作,且操作频繁变化时。
classDiagram
class IVisitor {
+Visit(Circle)*
+Visit(Box)*
}
class AreaVisitor {
+Visit(Circle)
+Visit(Box)
}
class Circle {
+Accept(IVisitor)
+Radius: float
}
class Box {
+Accept(IVisitor)
+Side: float
}
IVisitor <|-- AreaVisitor
Circle ..> IVisitor : accept
Box ..> IVisitor : accept
最简C++示例
class Circle; class Box;
class IVisitor
{
public:
virtual void Visit(Circle& C) = 0;
virtual void Visit(Box& B) = 0;
};
class Circle { public: void Accept(IVisitor& V) { V.Visit(*this); } float Radius; };
class Box { public: void Accept(IVisitor& V) { V.Visit(*this); } float Side; };
// 新增操作:不修改Circle/Box,只加新Visitor
class AreaVisitor : public IVisitor
{
public:
void Visit(Circle& C) override { float A = 3.14f * C.Radius * C.Radius; }
void Visit(Box& B) override { float A = B.Side * B.Side; }
};
UE中的应用
UGameplayEffect访问UAttributeSet:Effect 是访问者,Attribute 是被访问元素,不同 Effect 对属性执行不同操作- 编辑器的
FArchive序列化:Archive 作为访问者遍历对象树,执行序列化/反序列化/引用收集等操作 FExpressionVisitor(材质图节点遍历)
23. 解释器 Interpreter
原理与用途
定义一个语言的文法,并提供解释器来处理该语言的句子。用于脚本系统、配置解析、DSL。
最简C++示例
// 表达式接口
class IExpression { public: virtual int Evaluate() = 0; };
class NumberExpr : public IExpression
{
int Value;
public:
NumberExpr(int V) : Value(V) {}
int Evaluate() override { return Value; }
};
class AddExpr : public IExpression
{
IExpression *Left, *Right;
public:
AddExpr(IExpression* L, IExpression* R) : Left(L), Right(R) {}
int Evaluate() override { return Left->Evaluate() + Right->Evaluate(); }
};
// 解释 "1 + 2 + 3"
IExpression* Expr = new AddExpr(new AddExpr(new NumberExpr(1), new NumberExpr(2)), new NumberExpr(3));
int Result = Expr->Evaluate(); // = 6
UE中的应用
GameplayTag匹配语法:FGameplayTagQuery用类似语言的方式描述 Tag 匹配规则(Any/All/None)- 蓝图虚拟机:蓝图节点图本质上是一种可视化语言,UE 的 VM 解释执行
ini配置解析:GConfig->GetString()解析配置文件语法
// GameplayTagQuery 作为解释器
FGameplayTagQuery Query = FGameplayTagQuery::MakeQuery_MatchAnyTags(
FGameplayTagContainer::CreateFromArray({Tag_Burning, Tag_Frozen})
);
bool bMatch = Query.Matches(ActorTags);
总结速查表
| 类型 | 模式 | 一句话 | UE对应 |
|---|---|---|---|
| 创建 | 单例 | 全局唯一实例 | UGameInstanceSubsystem |
| 创建 | 工厂方法 | 子类决定创建哪个 | SpawnActor + TSubclassOf |
| 创建 | 抽象工厂 | 创建一系列相关对象 | DataAsset + 工厂类 |
| 创建 | 建造者 | 分步构建复杂对象 | FActorSpawnParameters |
| 创建 | 原型 | 克隆现有对象 | StaticDuplicateObject |
| 结构 | 适配器 | 转换接口 | UInterface |
| 结构 | 桥接 | 抽象与实现分离 | RHI 渲染接口 |
| 结构 | 组合 | 树形统一接口 | USceneComponent 层级 |
| 结构 | 装饰器 | 动态添加职责 | 动态挂载 UActorComponent |
| 结构 | 外观 | 简化复杂子系统 | UGameplayStatics |
| 结构 | 享元 | 共享细粒度对象 | UStaticMesh 共享、FName |
| 结构 | 代理 | 控制对象访问 | TSoftObjectPtr、网络 RPC |
| 行为 | 责任链 | 请求沿链传递 | Enhanced Input 优先级 |
| 行为 | 命令 | 操作封装为对象 | UGameplayAbility |
| 行为 | 迭代器 | 统一遍历集合 | TActorIterator |
| 行为 | 中介者 | 中间人协调通信 | AGameMode / AGameState |
| 行为 | 备忘录 | 捕获并恢复状态 | USaveGame |
| 行为 | 观察者 | 一对多事件通知 | Multicast Delegate |
| 行为 | 状态 | 状态决定行为 | 动画状态机、GAS Tag |
| 行为 | 策略 | 运行时替换算法 | UCharacterMovementComponent |
| 行为 | 模板方法 | 父类定义流程骨架 | BeginPlay / Tick |
| 行为 | 访问者 | 不改类增加操作 | GameplayEffect + AttributeSet |
| 行为 | 解释器 | 解析自定义语言 | GameplayTagQuery、蓝图VM |