我是从探索XNA框架来探讨这个问题的,但我想了解一般情况.
ISomeService someService = (ISomeService)Game.GetServices(typeof(ISomeService));
Run Code Online (Sandbox Code Playgroud)
然后我们对界面中的任何函数/属性做一些事情:
someService.DoSomething(); // let's say not a static method but doesn't matter
Run Code Online (Sandbox Code Playgroud)
我试图找出为什么这种实现比以下更好:
myObject = InstanceFromComponentThatWouldProvideTheService();
myObject.DoSomething();
Run Code Online (Sandbox Code Playgroud)
当您使用服务方式获取接口时,您实际上只是获取了提供服务的组件实例.对?你不能有一个接口"实例".而且只有一个类可以成为服务的提供者.所以你真正拥有的只是组件类的一个实例,唯一的区别是你只能访问组件对象的子集(界面中的任何子集).
这有什么不同于公共和私人方法和属性?换句话说,组件的公共方法/属性是 "接口",我们可以停止所有这些迂回.您仍然可以更改实现"接口"的方式而不会破坏任何内容(直到您更改方法签名,但这也会破坏服务实现).
无论如何,组件和服务之间将存在一对一的关系(多个类不能注册成为服务的提供者),并且我看不到类是提供者的不止一项服务(srp和所有).
所以我想我正在试图找出这种框架要解决的问题.我错过了什么?
And*_*ell 17
请允许我通过XNA本身的示例来解释它:
该ContentManager构造需要IServiceProvider.然后它使用它IServiceProvider来获取a IGraphicsDeviceService,它反过来用来获取GraphicsDevice它加载纹理,效果等内容.
它不能Game- 因为该类完全是可选的(并且在依赖程序集中).它不能采用GraphicsDeviceManager(常用的实现IGraphicsDeviceService),因为它Game是一个可选的辅助类来设置GraphicsDevice.
它不能GraphicsDevice直接使用,因为您可能在创建ContentManager之前创建了一个GraphicsDevice(这正是默认Game类所做的).因此,它需要一项服务,它可以从以后检索图形设备.
现在,这里是真正的踢球者:它可以采取IGraphicsDeviceService直接使用.但是:如果在未来的某个时间XNA团队添加(例如)AudioDevice某些内容类型所依赖的类,该怎么办?然后你必须修改ContentManager构造函数的方法签名来取一个IAudioDeviceService或者什么 - 这会破坏第三方代码.通过提供服务提供商可以避免此问题.
实际上 - 您不必等待XNA团队添加需要公共资源的新内容类型:当您编写自定义时,ContentTypeReader您可以访问IServiceProvider内容管理器并查询它以获取您喜欢的任何服务 - 甚至是您自己的服务!这样,您的自定义内容类型可以使用与第一类XNA图形类型相同的机制,而XNA代码无需了解它们或所需的服务.
(相反,如果您从未使用图形类型加载图形类型ContentManager,那么您永远不必为其提供图形设备服务.)
当然,对于像XNA这样的库来说,这一切都很好,这需要在不破坏第三方代码的情况下进行更新.特别是对于类似的东西ContentManager,可以由第三方扩展.
但是:我看到很多人在乱用DrawableGameComponent,发现你不能SpriteBatch轻易地分享它,所以创建某种精灵批处理服务来传递它.这比通常没有版本控制,程序集依赖性或第三方可扩展性要求的游戏所需的复杂程度要高得多.仅仅因为Game.Services存在,并不意味着你必须使用它!如果你可以直接传递东西(比如SpriteBatch实例) - 就这样做 - 它更简单,更明显.