Extra2D/docs/module_system.md

18 KiB
Raw Blame History

Extra2D 模块系统

概述

Extra2D 采用模块化架构设计,所有核心功能通过模块系统和服务系统管理。系统提供:

  • 统一的生命周期管理:初始化、关闭、依赖处理
  • 优先级排序:确保模块/服务按正确顺序初始化
  • 配置驱动:每个模块可独立配置
  • 依赖注入:通过服务定位器解耦模块间依赖
  • 可测试性:支持 Mock 服务进行单元测试

架构图

┌─────────────────────────────────────────────────────────────┐
│                      Application                             │
│  (协调模块和服务,通过服务定位器获取依赖)                       │
└─────────────────────────────────────────────────────────────┘
                              │
              ┌───────────────┴───────────────┐
              ▼                               ▼
┌─────────────────────────────┐   ┌─────────────────────────────┐
│      ModuleRegistry         │   │      ServiceLocator         │
│  (模块注册表,管理平台级模块) │   │  (服务定位器,管理运行时服务) │
└─────────────────────────────┘   └─────────────────────────────┘
              │                               │
        ┌─────┴─────┐                 ┌───────┴───────┐
        ▼           ▼                 ▼               ▼
┌───────────┐ ┌───────────┐   ┌───────────┐   ┌───────────┐
│  Config   │ │  Window   │   │  Scene    │   │  Timer    │
│  Module   │ │  Module   │   │  Service  │   │  Service  │
└───────────┘ └───────────┘   └───────────┘   └───────────┘
                                    │               │
                              ┌─────┴─────┐   ┌─────┴─────┐
                              ▼           ▼   ▼           ▼
                        ┌──────────┐ ┌──────────┐ ┌──────────┐
                        │  Event   │ │  Camera  │ │   ...    │
                        │  Service │ │  Service │ │          │
                        └──────────┘ └──────────┘ └──────────┘

模块 vs 服务

特性 模块 (Module) 服务 (Service)
用途 平台级初始化 运行时功能
生命周期 Application 管理 ServiceLocator 管理
依赖方式 通过 ModuleRegistry 通过 ServiceLocator
可替换性 编译时确定 运行时可替换
测试支持 需要重构 原生支持 Mock
示例 Window, Render, Config Scene, Timer, Event, Camera

模块优先级

模块按优先级从小到大初始化,关闭时逆序执行:

优先级值 枚举名称 用途 模块示例
0 Core 核心模块,最先初始化 Logger, Config, Platform, Window
100 Graphics 图形渲染 Render
200 Audio 音频系统 Audio
500 Resource 资源管理 Resource

服务优先级

服务按优先级从小到大初始化:

优先级值 枚举名称 用途 服务示例
0 Core 核心服务 -
100 Event 事件系统 EventService
200 Timer 计时器 TimerService
300 Scene 场景管理 SceneService
400 Camera 相机系统 CameraService
500 Resource 资源管理 -
600 Audio 音频系统 -

模块系统

IModuleConfig

模块配置接口,定义模块的元数据和配置:

class IModuleConfig {
public:
    virtual ~IModuleConfig() = default;
    
    virtual ModuleInfo getModuleInfo() const = 0;
    virtual std::string getConfigSectionName() const = 0;
    virtual bool validate() const = 0;
    virtual void resetToDefaults() = 0;
    virtual bool loadFromJson(const void* jsonData) = 0;
    virtual bool saveToJson(void* jsonData) const = 0;
    virtual void applyPlatformConstraints(PlatformType platform) {}
};

IModuleInitializer

模块初始化器接口,管理模块的生命周期:

class IModuleInitializer {
public:
    virtual ~IModuleInitializer() = default;
    
    virtual ModuleId getModuleId() const = 0;
    virtual ModulePriority getPriority() const = 0;
    virtual std::vector<ModuleId> getDependencies() const = 0;
    
    virtual bool initialize(const IModuleConfig* config) = 0;
    virtual void shutdown() = 0;
    virtual bool isInitialized() const = 0;
};

ModuleRegistry

模块注册表,管理所有模块:

class ModuleRegistry {
public:
    static ModuleRegistry& instance();
    
    ModuleId registerModule(
        UniquePtr<IModuleConfig> config,
        ModuleInitializerFactory factory
    );
    
    IModuleConfig* getModuleConfig(ModuleId id);
    IModuleInitializer* getInitializer(ModuleId id);
    std::vector<ModuleId> getInitializationOrder() const;
};

服务系统

IService

服务接口基类,所有服务必须实现:

class IService {
public:
    virtual ~IService() = default;
    
    virtual ServiceInfo getServiceInfo() const = 0;
    virtual bool initialize() = 0;
    virtual void shutdown() = 0;
    virtual void pause();
    virtual void resume();
    virtual void update(float deltaTime);
    virtual bool isInitialized() const;
    
    ServiceState getState() const;
    const std::string& getName() const;
};

ServiceLocator

服务定位器,实现依赖注入和服务发现:

class ServiceLocator {
public:
    static ServiceLocator& instance();
    
    // 注册服务实例
    template<typename T>
    void registerService(SharedPtr<T> service);
    
    // 注册服务工厂(延迟创建)
    template<typename T>
    void registerFactory(ServiceFactory<T> factory);
    
    // 获取服务
    template<typename T>
    SharedPtr<T> getService() const;
    
    // 检查服务是否存在
    template<typename T>
    bool hasService() const;
    
    // 批量操作
    bool initializeAll();
    void shutdownAll();
    void updateAll(float deltaTime);
    void pauseAll();
    void resumeAll();
    void clear();
};

内置服务

SceneService

场景管理服务,包装 SceneManager

class ISceneService : public IService {
public:
    virtual void runWithScene(Ptr<Scene> scene) = 0;
    virtual void replaceScene(Ptr<Scene> scene) = 0;
    virtual void pushScene(Ptr<Scene> scene) = 0;
    virtual void popScene() = 0;
    
    virtual Ptr<Scene> getCurrentScene() const = 0;
    virtual size_t getSceneCount() const = 0;
    
    virtual void render(RenderBackend& renderer) = 0;
};

TimerService

计时器服务,包装 TimerManager

class ITimerService : public IService {
public:
    virtual uint32 addTimer(float delay, Timer::Callback callback) = 0;
    virtual uint32 addRepeatingTimer(float interval, Timer::Callback callback) = 0;
    virtual void cancelTimer(uint32 timerId) = 0;
    virtual void pauseTimer(uint32 timerId) = 0;
    virtual void resumeTimer(uint32 timerId) = 0;
};

EventService

事件服务,整合 EventQueue 和 EventDispatcher

class IEventService : public IService {
public:
    virtual void pushEvent(const Event& event) = 0;
    virtual bool pollEvent(Event& event) = 0;
    
    virtual ListenerId addListener(EventType type, EventCallback callback) = 0;
    virtual void removeListener(ListenerId id) = 0;
    
    virtual void dispatch(Event& event) = 0;
    virtual void processQueue() = 0;
};

CameraService

相机服务,整合 Camera 和 ViewportAdapter

class ICameraService : public IService {
public:
    virtual void setPosition(const Vec2& position) = 0;
    virtual void setZoom(float zoom) = 0;
    virtual void setRotation(float degrees) = 0;
    
    virtual glm::mat4 getViewProjectionMatrix() const = 0;
    virtual Vec2 screenToWorld(const Vec2& screenPos) const = 0;
    
    virtual void setViewportConfig(const ViewportConfig& config) = 0;
    virtual void updateViewport(int width, int height) = 0;
};

使用示例

在 Application 中使用服务

// 获取服务
auto sceneService = Application::get().scenes();
auto timerService = Application::get().timers();
auto eventService = Application::get().events();
auto cameraService = Application::get().camera();

// 使用场景服务
sceneService->pushScene(myScene);

// 使用计时器服务
timerService->addTimer(1.0f, []() {
    E2D_LOG_INFO("Timer fired!");
});

// 使用事件服务
eventService->addListener(EventType::KeyDown, [](Event& e) {
    E2D_LOG_INFO("Key pressed: {}", e.key.keycode);
});

// 使用相机服务
cameraService->setPosition(Vec2(100.0f, 200.0f));
cameraService->setZoom(2.0f);

注册自定义服务

// 定义服务接口
class IAudioService : public IService {
public:
    virtual void playSound(const std::string& path) = 0;
    virtual void stopAll() = 0;
};

// 实现服务
class AudioService : public IAudioService {
public:
    ServiceInfo getServiceInfo() const override {
        ServiceInfo info;
        info.name = "AudioService";
        info.priority = ServicePriority::Audio;
        return info;
    }
    
    bool initialize() override {
        // 初始化音频系统...
        setState(ServiceState::Running);
        return true;
    }
    
    void shutdown() override {
        // 清理音频系统...
        setState(ServiceState::Stopped);
    }
    
    void playSound(const std::string& path) override {
        // 播放音效...
    }
    
    void stopAll() override {
        // 停止所有音效...
    }
};

// 注册服务
Application::get().registerService<IAudioService>(makeShared<AudioService>());

// 使用服务
auto audio = Application::get().getService<IAudioService>();
audio->playSound("explosion.wav");

测试时注入 Mock 服务

// 创建 Mock 服务
class MockSceneService : public ISceneService {
public:
    std::vector<std::string> sceneHistory;
    
    void pushScene(Ptr<Scene> scene) override {
        sceneHistory.push_back("push:" + scene->getName());
    }
    
    void popScene() override {
        sceneHistory.push_back("pop");
    }
    
    // 实现其他必要方法...
};

// 测试代码
void testSceneNavigation() {
    // 注入 Mock 服务
    auto mockService = makeShared<MockSceneService>();
    ServiceLocator::instance().registerService<ISceneService>(mockService);
    
    // 执行测试
    auto sceneService = ServiceLocator::instance().getService<ISceneService>();
    sceneService->pushScene(createTestScene("level1"));
    sceneService->pushScene(createTestScene("level2"));
    sceneService->popScene();
    
    // 验证结果
    assert(mockService->sceneHistory.size() == 3);
    assert(mockService->sceneHistory[0] == "push:level1");
    assert(mockService->sceneHistory[1] == "push:level2");
    assert(mockService->sceneHistory[2] == "pop");
}

创建新模块

步骤 1定义配置类

class MyModuleConfig : public IModuleConfig {
public:
    int someSetting = 42;
    
    ModuleInfo getModuleInfo() const override {
        ModuleInfo info;
        info.name = "MyModule";
        info.version = "1.0.0";
        info.priority = ModulePriority::Graphics;
        info.enabled = true;
        return info;
    }
    
    std::string getConfigSectionName() const override { return "my_module"; }
    bool validate() const override { return someSetting > 0; }
    void resetToDefaults() override { someSetting = 42; }
    bool loadFromJson(const void* jsonData) override;
    bool saveToJson(void* jsonData) const override;
};

步骤 2定义初始化器

class MyModuleInitializer : public IModuleInitializer {
public:
    ModuleId getModuleId() const override { return moduleId_; }
    ModulePriority getPriority() const override { return ModulePriority::Graphics; }
    std::vector<ModuleId> getDependencies() const override { return {}; }
    
    bool initialize(const IModuleConfig* config) override {
        if (initialized_) return true;
        
        const MyModuleConfig* cfg = dynamic_cast<const MyModuleConfig*>(config);
        if (!cfg) return false;
        
        // 执行初始化逻辑...
        
        initialized_ = true;
        E2D_LOG_INFO("MyModule initialized");
        return true;
    }
    
    void shutdown() override {
        if (!initialized_) return;
        // 执行清理逻辑...
        initialized_ = false;
        E2D_LOG_INFO("MyModule shutdown");
    }
    
    bool isInitialized() const override { return initialized_; }
    void setModuleId(ModuleId id) { moduleId_ = id; }

private:
    ModuleId moduleId_ = INVALID_MODULE_ID;
    bool initialized_ = false;
};

步骤 3注册模块

// my_module.cpp
#include <extra2d/config/module_registry.h>

namespace extra2d {

static ModuleId s_myModuleId = INVALID_MODULE_ID;

ModuleId get_my_module_id() { return s_myModuleId; }

void register_my_module() {
    if (s_myModuleId != INVALID_MODULE_ID) return;
    
    s_myModuleId = ModuleRegistry::instance().registerModule(
        makeUnique<MyModuleConfig>(),
        []() -> UniquePtr<IModuleInitializer> {
            auto initializer = makeUnique<MyModuleInitializer>();
            initializer->setModuleId(s_myModuleId);
            return initializer;
        }
    );
}

} // namespace extra2d

内置模块

Logger 模块

职责:管理日志系统初始化和关闭

配置

LoggerModuleConfig config;
config.logLevel = LogLevel::Info;
config.consoleOutput = true;
config.fileOutput = true;
config.logFilePath = "app.log";

Config 模块

职责:管理 ConfigManager 和应用配置

配置

ConfigModuleConfig config;
config.configPath = "config.json";
config.appConfig = AppConfig::createDefault();

Platform 模块

职责:平台检测和平台特定初始化

平台特定操作

  • Switch初始化 romfs 和 socket

Window 模块

职责:窗口创建和后端管理

后端支持

  • SDL2跨平台
  • GLFW跨平台
  • Switch原生

配置

WindowModuleConfig config;
config.windowConfig.title = "My App";
config.windowConfig.width = 1280;
config.windowConfig.height = 720;
config.windowConfig.vsync = true;

Render 模块

职责:渲染器初始化和管理

配置

RenderModuleConfig config;
config.backend = BackendType::OpenGL;
config.vsync = true;
config.targetFPS = 60;
config.multisamples = 4;

配置文件格式

模块配置使用 JSON 格式:

{
    "logger": {
        "logLevel": 2,
        "consoleOutput": true,
        "fileOutput": false
    },
    "window": {
        "title": "My Application",
        "width": 1280,
        "height": 720,
        "vsync": true
    },
    "render": {
        "targetFPS": 60,
        "multisamples": 4
    }
}

最佳实践

1. 模块用于平台初始化,服务用于运行时功能

// 模块:平台级初始化
class WindowModule : public IModuleInitializer {
    bool initialize(const IModuleConfig* config) override {
        // 创建窗口、初始化 OpenGL 上下文
    }
};

// 服务:运行时功能
class SceneService : public ISceneService {
    void update(float deltaTime) override {
        // 每帧更新场景
    }
};

2. 通过服务定位器解耦依赖

// 好的做法:通过服务定位器获取依赖
void MyNode::onUpdate(float dt) {
    auto camera = ServiceLocator::instance().getService<ICameraService>();
    auto pos = camera->screenToWorld(mousePos);
}

// 不好的做法:直接依赖 Application
void MyNode::onUpdate(float dt) {
    auto& camera = Application::get().camera();  // 耦合度高
}

3. 使用接口便于测试

// 定义接口
class IAudioService : public IService { ... };

// 生产环境使用真实实现
auto audio = makeShared<AudioService>();

// 测试环境使用 Mock
auto audio = makeShared<MockAudioService>();

4. 安全关闭

void shutdown() override {
    if (!initialized_) return; // 避免重复关闭
    
    // 清理资源
    resource_.reset();
    
    setState(ServiceState::Stopped);
    initialized_ = false;
}

调试

查看模块初始化顺序

auto order = ModuleRegistry::instance().getInitializationOrder();
for (ModuleId id : order) {
    auto* config = ModuleRegistry::instance().getModuleConfig(id);
    if (config) {
        auto info = config->getModuleInfo();
        E2D_LOG_INFO("Module: {} (priority: {})", 
                     info.name, static_cast<int>(info.priority));
    }
}

查看服务状态

auto services = ServiceLocator::instance().getAllServices();
for (const auto& service : services) {
    auto info = service->getServiceInfo();
    E2D_LOG_INFO("Service: {} (state: {})", 
                 info.name, static_cast<int>(info.state));
}

示例

完整示例请参考: