Manager、System、Handler 和 Service 应如何命名和区分?
结论
这四个后缀没有适用于所有项目的统一划分。命名时应根据类的具体职责来选择,并在项目内保持一致。
团队可以约定“玩家直接交互的叫 System,后台运行的叫 Manager”,但这不适合作为通用标准。玩家点击存档按钮后,可能依次触发 UI 处理器和存档服务。是否由玩家触发,并不能说明这些类各自负责什么。
四种后缀通常表达什么
| 后缀 | 常见含义 | 使用时需要明确的内容 |
|---|---|---|
Manager | 管理一组对象的注册、查找、生命周期,或协调多个对象 | 管理什么,以及具体管理哪些操作 |
System | 表示一个功能子系统,或在某种架构中执行一类处理 | 项目是否已经赋予 System 明确含义 |
Handler | 响应某个事件、命令、请求或回调 | 处理的输入是什么 |
Service | 向调用方提供一组相关能力,例如存档、寻路 | 对外提供哪些操作,以及职责边界在哪里 |
这些是常见用法,并非强制规则。Handler 可以调用 Service,System 也可能使用多个服务;后缀本身不会决定它们的依赖关系。
现有名称可以怎样调整
UnitManager
如果它主要保存并查找单位,可以根据实际职责考虑更具体的名称,比如 UnitRegistry 或 UnitRepository:
- 负责单位的注册、注销和查找,可以考虑
UnitRegistry。 - 负责单位数据的存取抽象,可以考虑
UnitRepository。 - 负责创建和销毁单位,可以考虑
UnitSpawner或UnitFactory,具体取决于它是否包含生成位置、时机等逻辑。
仅凭“保存所有单位的信息”还不足以确定唯一名称。如果它确实协调单位的完整生命周期,保留 UnitManager 也合理。
SaveSystem
如果它对外提供保存和读取游戏进度的能力,GameSaveService 能直接表达这个用途。如果项目一直用 System 表示功能子系统,也可以继续使用 SaveSystem。
如果一个类只负责将存档数据转换为字节或文本,SaveSerializer 会更准确;如果只负责文件读写,可以考虑 SaveFileStore。这些名称对应不同职责,不需要为了命名而全部拆成独立类。
UnitActionSystem
如果它集中更新或执行单位动作,现有名称可以成立。如果它只负责执行一个已选定的动作,UnitActionExecutor 可能更明确;如果它响应某条具体命令,可以使用对应的 Handler 名称。
在 ECS 等架构中,System 可能已有特定含义,应优先遵循所用架构的约定。原问题没有说明使用 ECS,不能仅凭名称推断其架构。
用调用关系区分职责
下面是一个简化的 C# 示例:按钮处理器响应点击,存档服务提供保存和读取能力。示例不包含实际存档实现。
public interface IGameSaveService
{
void SaveGame();
void LoadGame();
}
public sealed class SaveButtonHandler
{
private readonly IGameSaveService saveService;
public SaveButtonHandler(IGameSaveService saveService)
{
this.saveService = saveService;
}
public void HandleClick()
{
saveService.SaveGame();
}
}
从名称可以看出,SaveButtonHandler 负责处理按钮操作,IGameSaveService 提供存档服务。实际项目是否使用接口,以及如何接入 Unity 的按钮事件,需要按现有代码结构决定。
选择名称的实用步骤
- 用一句话描述类的主要职责,例如“记录当前已注册的单位并支持查找”。
- 优先选择能表达职责的名称,例如
UnitRegistry,再考虑是否需要通用后缀。 - 检查项目中同类职责是否已有命名约定,避免相同后缀在不同模块中含义不同。
- 如果需要用很多互不相关的动词才能描述清楚一个类,先检查它的职责是否过多。
不必仅为替换后缀而重命名所有类。可以优先检查名称无法让调用方判断用途,或类中聚集了多个无关职责的情况。
备注:内容仅供参考。
