diff --git a/src/Base/ServiceProvider.cpp b/src/Base/ServiceProvider.cpp index 1f99a53100..7401c3e9cf 100644 --- a/src/Base/ServiceProvider.cpp +++ b/src/Base/ServiceProvider.cpp @@ -26,8 +26,7 @@ #include "ServiceProvider.h" -Base::ServiceProvider& Base::ServiceProvider::get() +namespace Base { - static Base::ServiceProvider instance; - return instance; +Base::ServiceProvider globalServiceProvider; } diff --git a/src/Base/ServiceProvider.h b/src/Base/ServiceProvider.h index 738c56d172..10aad1032f 100644 --- a/src/Base/ServiceProvider.h +++ b/src/Base/ServiceProvider.h @@ -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(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(); + * @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 - 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> _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 -T* provideImplementation() +T* provideService() { - return ServiceProvider::get().provide(); + return globalServiceProvider.provide(); } +/** + * 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 -std::list provideAllImplementations() +std::list provideServiceImplementations() { - return ServiceProvider::get().all(); + return globalServiceProvider.all(); } +/** + * Registers implementation of service in the global service provider. + * + * @tparam T Service kind to obtain. + * @return List of available service implementation. + */ template -void implementContract(T* implementation) +void registerServiceImplementation(T* implementation) { - ServiceProvider::get().implement(implementation); + globalServiceProvider.registerImplementation(implementation); } } // namespace Base diff --git a/tests/src/Base/ServiceProvider.cpp b/tests/src/Base/ServiceProvider.cpp index 405c8cf134..0d6b41a773 100644 --- a/tests/src/Base/ServiceProvider.cpp +++ b/tests/src/Base/ServiceProvider.cpp @@ -62,7 +62,7 @@ TEST(ServiceProvider, provideImplementation) // Arrange Base::ServiceProvider serviceProvider; - serviceProvider.implement(new FirstServiceImplementation); + serviceProvider.registerImplementation(new FirstServiceImplementation); // Act auto implementation = serviceProvider.provide(); @@ -77,8 +77,8 @@ TEST(ServiceProvider, provideLatestImplementation) // Arrange Base::ServiceProvider serviceProvider; - serviceProvider.implement(new FirstServiceImplementation); - serviceProvider.implement(new SecondServiceImplementation); + serviceProvider.registerImplementation(new FirstServiceImplementation); + serviceProvider.registerImplementation(new SecondServiceImplementation); // Act auto implementation = serviceProvider.provide(); @@ -93,8 +93,8 @@ TEST(ServiceProvider, provideAllImplementations) // Arrange Base::ServiceProvider serviceProvider; - serviceProvider.implement(new FirstServiceImplementation); - serviceProvider.implement(new SecondServiceImplementation); + serviceProvider.registerImplementation(new FirstServiceImplementation); + serviceProvider.registerImplementation(new SecondServiceImplementation); // Act auto implementations = serviceProvider.all();