Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

游戏设计模式(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 叠层:对角色属性动态叠加/移除效果
  • UActorComponentbAutoActivate 控制装饰是否生效
// 运行时给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 是最典型的外观:PlaySound2DSpawnEmitterAtLocation 等封装了复杂的子系统调用
  • UKismetMathLibraryUKismetSystemLibrary 同理
  • 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 未处理的输入事件向父级传递
  • APlayerControllerAPawnACharacter 的输入处理链

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 / EndAbility
  • UInputAction 绑定:将输入事件映射为命令
  • 编辑器的 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-forfor (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,引擎定义调用时机,游戏代码实现具体行为
  • AGameModeInitGame / PostLogin / HandleMatchHasEnded 等回调
  • UUserWidgetNativeConstruct / 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