ServiceProvider: Better naming of methods

This commit renames methods of ServiceProvider to be easier to
understand. It also replaces the misleading singleton with more correct
here global instance of class.
This commit is contained in:
Kacper Donat
2025-01-04 13:08:40 +01:00
parent 8e17312d81
commit 3774830a46
3 changed files with 77 additions and 17 deletions

View File

@@ -26,8 +26,7 @@
#include "ServiceProvider.h"
Base::ServiceProvider& Base::ServiceProvider::get()
namespace Base
{
static Base::ServiceProvider instance;
return instance;
Base::ServiceProvider globalServiceProvider;
}

View File

@@ -36,6 +36,49 @@
namespace Base
{
/**
* Class that implements basic service container that can be used to obtain different implementation
* of various services.
*
* Primary use of such container is to provide ability to define global services that can be
* implemented within non-core modules. This for example allows to use code that is available only
* in Part module from Base with the only requirement being that Part implements specific interface
* and registers the service within service provider.
*
* For ease of use global service provider instance is provided with convenience functions:
* - Base::provideService
* - Base::provideServiceImplementations
* - Base::registerServiceImplementation
*
* As the example, we can define service that provides placement of sub objects in App:
* @code
* class SubObjectPlacementProvider
* {
* public:
* virtual Base::Placement calculate(SubObjectT object, Base::Placement basePlacement) const =
* 0;
* };
* @endcode
*
* App does not know how to implement this service, but it can be implemented within Part module:
* @code
* class AttacherSubObjectPlacement final: public App::SubObjectPlacementProvider { ... }
*
* // later in module initialization method
*
* Base::registerServiceImplementation<App::SubObjectPlacementProvider>(new
* AttacherSubObjectPlacement);
* @endcode
*
* This service can then be obtained inside other modules, without them being aware of the
* implementation - only the interface:
*
* @code
* auto subObjectPlacementProvider = Base::provideService<App::SubObjectPlacementProvider>();
* @endcode
*
* This function can (and should) be used as default for constructor injection of services.
*/
class BaseExport ServiceProvider
{
struct ServiceDescriptor
@@ -106,35 +149,53 @@ public:
* @tparam T Service interface
*/
template<typename T>
void implement(T* contract)
void registerImplementation(T* contract)
{
ServiceDescriptor descriptor {typeid(T).name(), contract};
_implementations[typeid(T).name()].push_front(descriptor);
}
static ServiceProvider& get();
private:
std::map<const char*, std::deque<ServiceDescriptor>> _implementations;
};
BaseExport extern ServiceProvider globalServiceProvider;
/**
* Obtains primary implementation of requested service from the global service provider.
*
* @tparam T Service kind to obtain.
* @return Primary implementation of the service or nullptr if there is no implementation available.
*/
template<typename T>
T* provideImplementation()
T* provideService()
{
return ServiceProvider::get().provide<T>();
return globalServiceProvider.provide<T>();
}
/**
* Obtains all available implementations of requested service in the global service provider.
*
* @tparam T Service kind to obtain.
* @return List of available service implementation.
*/
template<typename T>
std::list<T*> provideAllImplementations()
std::list<T*> provideServiceImplementations()
{
return ServiceProvider::get().all<T>();
return globalServiceProvider.all<T>();
}
/**
* Registers implementation of service in the global service provider.
*
* @tparam T Service kind to obtain.
* @return List of available service implementation.
*/
template<typename T>
void implementContract(T* implementation)
void registerServiceImplementation(T* implementation)
{
ServiceProvider::get().implement<T>(implementation);
globalServiceProvider.registerImplementation<T>(implementation);
}
} // namespace Base

View File

@@ -62,7 +62,7 @@ TEST(ServiceProvider, provideImplementation)
// Arrange
Base::ServiceProvider serviceProvider;
serviceProvider.implement<SimpleService>(new FirstServiceImplementation);
serviceProvider.registerImplementation<SimpleService>(new FirstServiceImplementation);
// Act
auto implementation = serviceProvider.provide<SimpleService>();
@@ -77,8 +77,8 @@ TEST(ServiceProvider, provideLatestImplementation)
// Arrange
Base::ServiceProvider serviceProvider;
serviceProvider.implement<SimpleService>(new FirstServiceImplementation);
serviceProvider.implement<SimpleService>(new SecondServiceImplementation);
serviceProvider.registerImplementation<SimpleService>(new FirstServiceImplementation);
serviceProvider.registerImplementation<SimpleService>(new SecondServiceImplementation);
// Act
auto implementation = serviceProvider.provide<SimpleService>();
@@ -93,8 +93,8 @@ TEST(ServiceProvider, provideAllImplementations)
// Arrange
Base::ServiceProvider serviceProvider;
serviceProvider.implement<SimpleService>(new FirstServiceImplementation);
serviceProvider.implement<SimpleService>(new SecondServiceImplementation);
serviceProvider.registerImplementation<SimpleService>(new FirstServiceImplementation);
serviceProvider.registerImplementation<SimpleService>(new SecondServiceImplementation);
// Act
auto implementations = serviceProvider.all<SimpleService>();