欢迎光临散文网 会员登陆 & 注册

《游戏编程模式》笔记——服务定位器

2023-09-19 16:56 作者:黑白色的枫  | 我要投稿

意图

提供服务的全局接入点,避免使用者和实现服务的具体类耦合。

模式

服务类定义了一堆操作的抽象接口。具体的服务提供者来实现这个接口。分离的服务定位器提供了通过查询获取服务的方法,同时隐藏了服务提供者的具体细节和定位它的过程。

何时使用

少用。

服务定位器是更加灵活,更加可配置的单例模式。用得好可以用很小的运行时开销,换取很大的灵活性。用得不好,会带来单例模式的所有缺点已经更多的运行时开销。

在需要功能可以全局访问时,并且实现类可能会运行时切换,可以使用该模式。

设计决策

服务是何时被定位的?

外部代码注册:

简单快捷。获取服务的函数简单的返回指针,这通常会被编译器内嵌,我们几乎没有付出性能损失就获得了很好的抽象层。

可以控制如何构建提供者。

可以在游戏运行时改变服务。

但是定位器会依赖外部代码。任何访问服务的代码必需假定在某处的代码已经注册过服务。如果没有做初始化,游戏可能会崩溃或者不工作。

在编译时绑定:

快速。所有工作在编译时完成,运行时无需完成任何工作,是最快的方案。

保证服务是可用的。编译时就进行了定位,可以保存游戏完成编译后,服务一定是可用的。

缺点是无法轻易改变服务。由于绑定是发生在编译时,任何时候想要改变服务,都要重新编译并重启游戏。

运行时设置:

使用反射在运行时实例化对象。

可以更换服务而无需重新编译。

非程序员也可以改变服务。

统一的代码库可以同时支持多种设置。

复杂。这个方案是重量级的,需要创建设置系统来实现外部定位服务。

加载服务需要时间,虽然缓存可以最小化消耗,但是首次使用服务时的消耗还是不可避免的。

如果服务不能被定位怎么办?

让使用者处理它:

让使用者决定如何掌控失败。如果定位器不能定义全面的政策应对所有的情况,就将失败传回去,让使用者决定什么是正确的回应。

挂起游戏:

使用断言挂起游戏。

使用者不必处理缺失的服务。

如果服务没有找到,游戏会挂起。这会强迫我们解决定位服务的漏洞,但被阻塞的所有人都得等待漏洞修复。

返回空服务:

使用者不必处理缺失的服务。保证了总是会返回可用的服务,简化了使用服务的代码。

如果服务不可用,游戏仍将继续。缺点是较难查找缺失服务的漏洞,空服务会导致游戏不会像期望的那样行动。需要配合一些日志来查找漏洞。

服务的范围有多大?

如果是全局可访问:

鼓励整个代码库使用同样的服务。大多数服务都被设计成单一的。整个代码库接触到相同的服务,可以避免代码因为不能获取“真正的”服务而到处实例化提供者。

但是失去了何时何地使用服务的控制权,全局化的代价是任何东西都能接触它。

如果接触被限制在某个类中:

控制了耦合,通过显式限制服务到继承树的一个分支上,应该解耦的系统保持了解耦。

缺点是可能导致重复的付出。如果一对无关的类需要接触服务,每个类都要拥有服务的引用,无论谁定位或注册服务,都要在这些类之间重复处理。


服务定位模式是单例的兄弟,根据需要使用更合适的一种。

Unity的GetComponent()方法中使用了这个模式,协调它的组件模式。


参考

《游戏编程模式》

《游戏编程模式》笔记——服务定位器的评论 (共 条)

分享到微博请遵守国家法律