65.9K
CodeProject 正在变化。 阅读更多。
Home

C++ 中的服务定位器模式实现

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.20/5 (3投票s)

2008 年 2 月 18 日

CPOL

3分钟阅读

viewsIcon

41116

downloadIcon

488

服务定位器可以用来解耦类,从而改善整体设计,并显著帮助单元测试。

引言

本文假定读者了解服务定位器模式。本文使用来自 Martin Fowler 的 控制反转容器和依赖注入模式的术语和代码示例。另请参阅 CodeProject 文章 服务定位器模式的基本介绍

背景

典型的例子是 C# 和 Java。 本文提供了 C++ 中一个简单但完整的服务定位器框架。

服务定位器背后的基本思想是能够使用存储库注册一个或多个类,然后要求存储库使用 ID 而不是实际的类名来创建这些类的实例。通过这样做,它使客户端代码与类的实际实现解耦,允许客户端注册相同接口的不同实现,从而能够在不更改使用该类的代码的情况下交换不同的功能集。这也有助于单元测试,因为对通常会被硬编码的类的引用不再需要了。

最后,这也减少了构建依赖关系。

用法预览

在本文中,使用了 Martin Fowler 的示例类:MovieFinder是一个接口(抽象纯虚类),而ColonDelimitedMovieFinder是一个实现MovieFinder的类。

服务定位器代码将允许我们使用字符串 ID(例如“finder”)注册ColonDelimitedMovieFinder,然后通过仅使用字符串名称“finder”创建ColonDelimitedMovieFinder类的实例,将引用分配给一个MovieFinder指针。

注册类的示例,将其存储在字符串 ID "finder" 下

locator.register_class<ColonDelimitedMovieFinder>( "finder" );

创建此类的实例的示例

MovieFinder* finder = locator.get_single_instance<MovieFinder>( "finder" );

Using the Code

(你只需要一个头文件,servicelocator.h。使用命名空间sl。)

interface_t派生你的接口(纯虚抽象类)。例子

struct MovieFinder : sl::interface_t
{
    virtual vector<Movie> findAll() = 0;
};

member_t派生你的模板类,将类名作为模板参数传递。例子

class ColonDelimitedMovieFinder : public sl::member_t<ColonDelimitedMovieFinder>
{ ...

创建一个servicelocator_t的实例。例子

sl::servicelocator_t locator;

使用register_class方法注册类。要注册的类是模板参数。 函数参数是表示类的字符串 ID。例子

locator.register_class<ColonDelimitedMovieFinder>( "finder" ); 

现在,可以使用ColonDelimitedMovieFinder的实例创建上面的字符串 ID(例如“finder”),而无需按名称引用ColonDelimitedMovieFinder。假设ColonDelimitedMovieFinder被重新定义为实现MovieFinder接口,如下所示

class ColonDelimitedMovieFinder : public sl::member_t<ColonDelimitedMovieFinder>, 
                                  public MovieFinder

然后,有两种创建ColonDelimitedMovieFinder实例的方法。一种作为单例(以便对创建的所有后续调用都返回相同的实例),另一种作为瞬时实例,每次调用都会创建一个新实例。

创建单例实例的调用是get_single_instance,它看起来像这样

MovieFinder* finder = locator.get_single_instance<MovieFinder>( "finder" );

(再次注意,没有引用类ColonDelimitedMovieFinder,但这就是创建的内容,因为字符串 ID "finder" 之前已使用ColonDelimitedMovieFinder注册了。)请注意,从get_single_instance返回的对象不需要释放。 仅创建一个实例,并且由服务定位器拥有。当locator对象超出范围或被释放时,所有单例都会被释放。

创建实例的第二种方法是通过get_new_instance,它看起来像这样

auto_ptr<MovieFinder> finder = locator.get_new_instance<MovieFinder>( "finder" );

为了方便起见,get_new_instance返回一个auto_ptr,它比原始指针更安全。但是,如果客户端不需要auto_ptr对象,则只需在auto_ptr上调用release()并获取原始对象,然后客户端可以根据需要进行管理。但在这种情况下,客户端有责任最终在原始对象上调用delete

© . All rights reserved.