####简单说,就是某个系统作为一个服务,对全局系统可见.

Service Locator (服务定位)

```
//简单粗暴的代码, 使用声音系统 // Use a static class?
AudioSystem::playSound(VERY_LOUD_BANG); // Or maybe a singleton?
AudioSystem::instance()->playSound(VERY_LOUD_BANG);
``` 类比:
如果我换了电话号码,需要通知我所有联系人,我换了电话号码
如果有一个提供个人信息的服务, 我只需要更新我的个人信息, 别人就可以查到我最新的电话号码 ### 模式定义
service类定义了抽象的操作借口, 一个具体的服务提供者实现这些接口.
service locator 找到合适的服务提供者,并且隐藏服务者具体类型和查找过程. ### 何时使用
某段程序 需要在任何时候,任何地方进行访问, 这样会带来麻烦,
比如说单例模式, 服务定位也有同样的问题. 尽量少的使用! 带来灵活性的同时,性能会下降. ### 注意事项
保证服务能被定位到
定位是全局访问的. 但有些服务在某些特定场景下才能正常使用. ### Sample Code
``` // Service
class Audio
{
public:
virtual ~Audio() {}
virtual void playSound(int soundID) = ;
virtual void stopSound(int soundID) = ;
virtual void stopAllSounds() = ;
}; // Service Provider class ConsoleAudio : public Audio {} // Locator
class Locator
{
public:
static Audio* getAudio() { return service_; } static void provide(Audio* service)
{
service_ = service;
} private:
static Audio* service_;
}; //游戏启动时
Audio *audio = Locator::getAudio();
audio->playSound(VERY_LOUD_BANG); //使用定位
Audio *audio = Locator::getAudio();
audio->playSound(VERY_LOUD_BANG); // 当所使用定位的时候, 服务提供还没有设置, 将会出错, 所谓我们提供一个默认的服务 class NullAudio: public Audio
{
public:
virtual void playSound(int soundID) { /* Do nothing. */ }
virtual void stopSound(int soundID) { /* Do nothing. */ }
virtual void stopAllSounds() { /* Do nothing. */ }
}; class Locator
{
public:
static void initialize() { service_ = &nullService_; } static Audio& getAudio() { return *service_; } static void provide(Audio* service)
{
if (service == NULL)
{
// Revert to null service.
service_ = &nullService_;
}
else
{
service_ = service;
}
} private:
static Audio* service_;
static NullAudio nullService_;
}; ``` ### 装饰器模式 ```
\\ 声音执行的log类 class LoggedAudio : public Audio
{
public:
LoggedAudio(Audio &wrapped)
: wrapped_(wrapped)
{} virtual void playSound(int soundID)
{
log("play sound");
wrapped_.playSound(soundID);
} virtual void stopSound(int soundID)
{
log("stop sound");
wrapped_.stopSound(soundID);
} virtual void stopAllSounds()
{
log("stop all sounds");
wrapped_.stopAllSounds();
} private:
void log(const char* message)
{
// Code to log message...
} Audio &wrapped_;
}; // 把服务提供者换成装饰之后的类
void enableAudioLogging()
{
// Decorate the existing service.
Audio *service = new LoggedAudio(Locator::getAudio()); // Swap it in.
Locator::provide(service);
}
``` ### 设计判断 #### 服务如何定位 ```
外部代码注册
. 快速简单
. 我们控制提供者的构建
. 可以在运行时改变服务
. 定位依赖于外部代码
编译期绑定
. 快速
. 保证服务可用
. 不能很容易的改变服务
运行时配置
. 改变服务不用重新编译
. 不用程序来修改服务(让策划配置)
. 可以提同时提供多个服务(不同的配置)
. 复杂
. 加载服务耗时(解析配置,等等)
``` #### 服务不能被定位到的时候
```
让用户处理
. 用户决定怎么面对错误
. 服务的用户必须处理错误
关闭游戏
. 用户不必处理丢失服务
. 如果服务找不到,就关闭游戏(容易debug, 但是会让使用这个服务的同事头疼)
返回一个null服务(默认服务)
. 用户不必处理丢失服务
. 游戏会继续运行,即使服务丢失(debug困难)
``` #### 服务的作用域
```
全局访问
. 服务提供者可控制, 禁止到处实例服务提供者
. 在哪使用和何时使用服务, 我们无法控制
受限访问
. 控制耦合, 把服务控制在一个继承树里, 系统里不耦合的部分还保持不耦合
. 导致重复. 比如不同的类都要保存一个服务类的引用. 恰当的设置服务的作用域, 比如说网络服务限制在online class里面访问, 而log系统则是全局的.
``` ## see also
服务定位类似于单例, 根据需要不同选用合适的设计
unity 融合了服务定位与组件模式, GetComponent可以当作获取服务.
XNA 框架 Game 类的实例有一个GameServices对象, 可以用来注册, 定位任何类型的服务

16_游戏编程模式ServiceLocator 服务定位的更多相关文章

  1. 游戏编程模式KeyNote

    [游戏编程模式KeyNote] 1.命令模式. 重做在游戏中并不常见,但重放常见.一种简单的重放实现是记录游戏每帧的状态,这样它可以回放,但那会消耗太多的内存.相反,很多游戏记录每个实体每帧运行的命令 ...

  2. 游戏编程模式 Game Programming Patterns (Robert Nystrom 著)

    第1篇 概述 第1章 架构,性能和游戏 (已看) 第2篇 再探设计模式 第2章 命令模式 (已看) 第3章 享元模式 (已看) 第4章 观察者模式 (已看) 第5章 原型模式 (已看) 第6章 单例模 ...

  3. 15_游戏编程模式EventQueue

    #### 两个例子 .GUI event loop ``` while (running) { // 从事件队列里获取一个事件 Event event = getNextEvent(); // Han ...

  4. 游戏编程算法与技巧 Game Programming Algorithms and Techniques (Sanjay Madhav 著)

    http://gamealgorithms.net 第1章 游戏编程概述 (已看) 第2章 2D图形 (已看) 第3章 游戏中的线性代数 (已看) 第4章 3D图形 (已看) 第5章 游戏输入 (已看 ...

  5. DirectX游戏编程入门

    刚开始学习D3D,安装完DirectX9后,在VS2008中新建Win32项目· ----------------------------------------------------------- ...

  6. 为了支持AOP的编程模式,我为.NET Core写了一个轻量级的Interception框架[开源]

    ASP.NET Core具有一个以ServiceCollection和ServiceProvider为核心的依赖注入框架,虽然这只是一个很轻量级的框架,但是在大部分情况下能够满足我们的需要.不过我觉得 ...

  7. PHP中应用Service Locator服务定位及单例模式

    单例模式将一个对象实例化后,放在静态变量中,供程序调用. 服务定位(ServiceLocator)就是对象工场Factory,调用者对象直接调用Service Locator,与被调用对象减轻了依赖关 ...

  8. Windows游戏编程之从零开始d

    Windows游戏编程之从零开始d I'm back~~恩,几个月不见,大家还好吗? 这段时间真的好多童鞋在博客里留言说或者发邮件说浅墨你回来继续更新博客吧. woxiangnifrr童鞋说每天都在来 ...

  9. DirectX 11游戏编程学习笔记之8: 第6章Drawing in Direct3D(在Direct3D中绘制)(习题解答)

            本文由哈利_蜘蛛侠原创,转载请注明出处.有问题欢迎联系2024958085@qq.com         注:我给的电子版是700多页,而实体书是800多页,所以我在提到相关概念的时候 ...

随机推荐

  1. 鸟哥的Linux私房菜-第一部分-第2章Linux如何学习

    第2章 Linux如何学习 Linux可以干什么 企业级:网络服务器.金融数据库.大型企业网管环境.高性能计算.集群 个人:桌面计算机.手机.PDA(掌上电脑,这个电脑的意义十分广泛,在不同的场景下有 ...

  2. Dockerfile学习(一)

    FROM指令: 格式为:FROM<image>:<tag>或者FROM<image> Dockerfile的第一条指令必须是FROM,用来指定要制作的镜像继承自哪个 ...

  3. "export" in SHELL

    在shell中,若某一变量需要在随后的子程序中运行,则需要以 export 来使变量变成环境变量: export var export的用法总结: 1:一个shell中用export定义的变量,只对当 ...

  4. PL/SQL不能格式化SQL:--PL/SQL Beautifier could not parse text

    PL/SQL sql语句美化器点击没有反应.查看下面提示PL/SQL Beautifier could not parse text.本人此次产生的原因是sql语句语法错误. 工具栏处(如果没有此按钮 ...

  5. 【转】Python max内置函数详细介绍

    #max() array1 = range(10) array2 = range(0, 20, 3) print('max(array1)=', max(array1)) print('max(arr ...

  6. Loadrunder之脚本篇——参数化同行取值

    select next row 记录选择方式 Same line as,这个选项只有当参数多余一个时才会出现,其作用是根据某一个参数的行号取同一行. 例中的做法如下: 将多个参数存放在一个参数文件中: ...

  7. 每天一个Linux命令(48)ping命令

        ping命令用来测试主机之间网络的连通性.     (1)用法:     用法:  ping [参数] [主机名或IP地址]     (2)功能:     功能:  确定网络和各外部主机的状态 ...

  8. second application:use an arcgis.com webmap

    <!DOCTYPE html> <html> <head> <title>Create a Web Map</title> <meta ...

  9. 【leetcode刷题笔记】Text Justification

    Given an array of words and a length L, format the text such that each line has exactly L characters ...

  10. uboot相关的几篇好文

    http://www.eeworld.com.cn/mcu/2015/0727/article_21246.html http://blog.csdn.net/kernel_yx/article/de ...