#service #thread-safe #service-provider #locator

service-locator

线程安全的泛型服务定位器

2 个不稳定版本

0.2.0 2023年6月19日
0.1.0 2023年6月12日

695游戏开发

Download history 107/week @ 2024-03-11 24/week @ 2024-04-01 7/week @ 2024-06-10 41/week @ 2024-06-17 32/week @ 2024-06-24

每月80次下载

无许可

14KB
176

服务定位器模式 泛型实现

这是一个线程安全的泛型服务定位器实现,可以与任何特例对象一起使用。

描述

此模式用于提供对服务的全局访问,安全地,而不将服务与其使用的代码耦合。有关此模式的更多信息,请参阅 Robert Nyström 的书籍 Game Programming Patterns

此模式的关键概念是

  • 服务 - 定义服务(一个特质)的接口。
  • 服务提供者 - 服务(实现特质)的实现。
  • 服务定位器 - 定位服务提供者的对象。

用法

服务定位器是一个静态对象,可用于提供和请求服务。内部,它使用 RwLock 以确保线程安全。服务定位器是服务特质对象的泛型。

示例

use service_locator::ServiceLocator;

enum Sound {
    Beep,
    Laser,
}

// The service.

trait Audio {
    fn play(&mut self, sound: Sound) {
        // Some stuff.
    }

    fn stop(&mut self, sound: Sound) {
        // Some stuff.
    }

    fn stop_all(&mut self) {
        // Some stuff.
    }

    fn is_playing(&self, sound: Sound) -> bool {
        false
    }
}

// The service providers.

#[derive(Default)]
struct SDLAudio {
    // Some stuff.
}

impl Audio for SDLAudio {
    // Use the default implementation as it is an example.
}

#[derive(Default)]
struct OpenALAudio {
    // Some stuff.
}

impl Audio for OpenALAudio {
    // Use the default implementation as it is an example.
}

static AUDIO_SERVICE_LOCATOR: ServiceLocator<dyn Audio + Send + Sync> = ServiceLocator::new();

// The service is not provided yet.
assert!(AUDIO_SERVICE_LOCATOR.service().is_err());

// Provide the service.
AUDIO_SERVICE_LOCATOR.provide(Box::new(SDLAudio::default()));

// The service is now provided.
assert_eq!(AUDIO_SERVICE_LOCATOR.service().unwrap().is_playing(Sound::Beep), false);

// The service can be mutably borrowed.
let mut service = AUDIO_SERVICE_LOCATOR.service_mut().unwrap();
service.stop_all();

// IMPORTANT: Drop the service, as it's a guard, before to request it again to avoid a deadlock.
// Before we didn't drop the service because we didn't bind the service to a variable.
drop(service);

// Change the service provider.
AUDIO_SERVICE_LOCATOR.provide(Box::new(OpenALAudio::default()));

// The service is now from the new provider.
let is_playing_laser = AUDIO_SERVICE_LOCATOR.service()
    // The closure is executed only if the service is provided,
    // and ensures that the service is dropped after the closure execution.
    .map(|service| service.is_playing(Sound::Laser))
    .unwrap();

assert_eq!(is_playing_laser, false);

请记住处理错误,而不是使用 unwrap()。它用于示例中,出于简单起见,因为它作为测试运行。

日志记录

该软件包使用 log 软件包进行日志记录。默认情况下禁用功能。

依赖项

~88KB