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

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. JAVA & C++ 多态

    多态,也叫动态绑定. Java: class A { public void f1() { System.out.println("A:f1"); } public void f2 ...

  2. Hadoop学习基础之三:MapReduce

    现在是讨论这个问题的不错的时机,因为最近媒体上到处充斥着新的革命所谓“云计算”的信息.这种模式需要利用大量的(低端)处理器并行工作来解决计算问题.实际上,这建议利用大量的低端处理器来构建数据中心,而不 ...

  3. Python 3 文件和字符编码

     一.文件: 打开文件的模式有: r,只读模式(默认). w,只写模式. 不可读,不存在则创建:存在则删除内容 a,追加模式. 可读,不存在则创建:存在则只追加内容 "+"表示可以 ...

  4. Funq之Lambda表达式入门

    今天接受了一个Tranning关于.net3.5 framework中的new feature. 其中最不明白的还是Lambda表达式.回来后又仔细的思考了一番,总算有点体会在这里写一下.既然是入门, ...

  5. SQL 根据IF判断,SET字段值

    当INVOICE_STATUS值为1时,赋值为2,否者赋值为原来的值 UPDATE T_INVOICE SET DOWNLOAD_COUNT = DOWNLOAD_COUNT + 1, INVOICE ...

  6. Android摄像头测量尺(Advanced Ruler Pro)使用方法

    http://www.cnblogs.com/sinojelly/archive/2010/08/13/1799341.html Advanced Ruler Pro是一个Android手机应用程序, ...

  7. Python编程-多线程

    一.python并发编程之多线程 1.threading模块 multiprocess模块的完全模仿了threading模块的接口,二者在使用层面,有很大的相似性,因而不再详细介绍 1.1 开启线程的 ...

  8. Python编程-架构、Socket

    一.客户端/服务器架构 1.C/S架构 Client/Server架构,即服务器/客户端架构. 客户端和服务器端的程序不同,用户的程序主要在客户端,服务器端主要提供数据管理.数据共享.数据及系统维护和 ...

  9. 七 、linux正则表达式

    为处理大量的字符串而定义的一套规则和方法 1)linux正则表达式以行为单位处理 2)alians grep = “grep –color=auto”,让匹配的内容显示颜色 3)注意字符集,expor ...

  10. id和NSObject *和instanceType的区别与联系

    id 被成为万能指针,也就是可以指向任何对象. NSObject * 本身就是定义指向NSObject类型的指针. 那么这两者有什么区别吗? 这两者都是既可以作为返回值,又可以作为变量修饰.而其主要区 ...