├── ServiceLocator.cpp ├── CMakeLists.txt ├── ServiceLocator.hpp ├── ServiceLocator.inl ├── LICENSE ├── README.md ├── single_include └── ServiceLocator.hpp └── Test.cpp /ServiceLocator.cpp: -------------------------------------------------------------------------------- 1 | #include "ServiceLocator.hpp" 2 | 3 | ServiceLocator::ServiceLocator() 4 | : instances(), creators() 5 | { 6 | } 7 | 8 | ServiceLocator::~ServiceLocator() 9 | { 10 | clear(); 11 | } 12 | 13 | void ServiceLocator::clear() 14 | { 15 | instances.clear(); 16 | creators.clear(); 17 | } -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | 3 | project (ServiceLocator) 4 | 5 | set(HEADERS 6 | "ServiceLocator.hpp" 7 | ) 8 | 9 | set(SOURCES 10 | "ServiceLocator.cpp" 11 | ) 12 | 13 | set(INLINES 14 | "ServiceLocator.inl" 15 | ) 16 | 17 | add_library(${PROJECT_NAME} ${HEADERS} ${SOURCES} ${INLINES}) 18 | target_include_directories(${PROJECT_NAME} PUBLIC "./") 19 | 20 | add_executable(${PROJECT_NAME}Test Test.cpp) 21 | target_link_libraries(${PROJECT_NAME}Test ${PROJECT_NAME}) 22 | -------------------------------------------------------------------------------- /ServiceLocator.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | class ServiceLocator 8 | { 9 | public: 10 | ServiceLocator(); 11 | ~ServiceLocator(); 12 | 13 | void clear(); 14 | 15 | template 16 | void registerInstance(T* instance = new T()); 17 | 18 | template 19 | void registerCreator(std::function()> creator = []() { return std::make_shared(); }); 20 | 21 | template 22 | std::shared_ptr resolve() const; 23 | 24 | private: 25 | std::unordered_map> instances; 26 | std::unordered_map()>> creators; 27 | }; 28 | 29 | #include "ServiceLocator.inl" 30 | -------------------------------------------------------------------------------- /ServiceLocator.inl: -------------------------------------------------------------------------------- 1 | #include "ServiceLocator.hpp" 2 | 3 | #include 4 | 5 | template 6 | void ServiceLocator::registerInstance(T* instance) 7 | { 8 | const size_t hash = typeid(T).hash_code(); 9 | if (instances.find(hash) == instances.end()) 10 | instances.emplace(hash, std::shared_ptr(instance)); 11 | } 12 | 13 | template 14 | void ServiceLocator::registerCreator(std::function()> creator) 15 | { 16 | const size_t hash = typeid(T).hash_code(); 17 | if (creators.find(hash) == creators.end()) 18 | creators.emplace(hash, creator); 19 | } 20 | 21 | template 22 | std::shared_ptr ServiceLocator::resolve() const 23 | { 24 | const size_t hash = typeid(T).hash_code(); 25 | auto itr1 = instances.find(hash); 26 | if (itr1 != instances.end()) 27 | return std::static_pointer_cast(itr1->second); 28 | 29 | auto itr2 = creators.find(hash); 30 | if (itr2 != creators.end()) 31 | return std::static_pointer_cast(itr2->second()); 32 | 33 | return nullptr; 34 | } 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Seng 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # C++ Simple ServiceLocator # 2 | A simple implementation of the service locator design pattern in C++. 3 | 4 | ## Usage ## 5 | 6 | ### Single Instance ### 7 | Register an instance: 8 | ```cpp 9 | ServiceLocator locator; 10 | locator.registerInstance(new MathService()); 11 | ``` 12 | And resolve it somewhere else: 13 | ```cpp 14 | auto svc1 = locator.resolve(); 15 | auto svc2 = locator.resolve(); // <= same instance 16 | ``` 17 | 18 | 19 | ### Lazy Initialization ### 20 | Register a delegate which creates a shared pointer to the corresponding instance: 21 | ```cpp 22 | ServiceLocator locator; 23 | locator.registerCreator([]() { return std::make_shared(); }); 24 | ``` 25 | Everytime you call `resolve`, the service locator will call the delegate and return the pointer: 26 | ```cpp 27 | auto svc1 = locator.resolve(); 28 | auto svc2 = locator.resolve(); // <= not the same instance 29 | ``` 30 | 31 | ### Clearing all registrations 32 | 33 | You can clear all registrations manually (will be called in destructor automatically): 34 | ```cpp 35 | locator.clear(); 36 | ``` 37 | 38 | ## License ## 39 | 40 | You can redistribute it and/or modify it under the terms of the MIT license. See [LICENSE][1] for details. 41 | 42 | [1]:LICENSE -------------------------------------------------------------------------------- /single_include/ServiceLocator.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | class ServiceLocator 9 | { 10 | public: 11 | ServiceLocator() : instances(), creators() {}; 12 | ~ServiceLocator() { clear(); } 13 | 14 | void clear() 15 | { 16 | instances.clear(); 17 | creators.clear(); 18 | } 19 | 20 | template 21 | void registerInstance(T* instance) 22 | { 23 | const size_t hash = typeid(T).hash_code(); 24 | if (instances.find(hash) == instances.end()) 25 | instances.emplace(hash, std::shared_ptr(instance)); 26 | } 27 | 28 | template 29 | void registerCreator(std::function()> creator) 30 | { 31 | const size_t hash = typeid(T).hash_code(); 32 | if (creators.find(hash) == creators.end()) 33 | creators.emplace(hash, creator); 34 | } 35 | 36 | template 37 | std::shared_ptr resolve() const 38 | { 39 | const size_t hash = typeid(T).hash_code(); 40 | auto itr1 = instances.find(hash); 41 | if (itr1 != instances.end()) 42 | return std::static_pointer_cast(itr1->second); 43 | 44 | auto itr2 = creators.find(hash); 45 | if (itr2 != creators.end()) 46 | return std::static_pointer_cast(itr2->second()); 47 | 48 | return nullptr; 49 | } 50 | 51 | private: 52 | std::unordered_map> instances; 53 | std::unordered_map()>> creators; 54 | }; 55 | -------------------------------------------------------------------------------- /Test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | //interface 5 | class IMathService 6 | { 7 | public: 8 | virtual ~IMathService() {}; 9 | 10 | virtual float add(const float& a, const float& b) = 0; 11 | virtual float subtract(const float& a, const float& b) = 0; 12 | virtual float multiply(const float& a, const float& b) = 0; 13 | virtual float divide(const float& a, const float& b) = 0; 14 | }; 15 | 16 | //implementation 17 | class MathService : public IMathService 18 | { 19 | public: 20 | int state; 21 | 22 | float add(const float& a, const float& b) override { return a + b; } 23 | float subtract(const float& a, const float& b) override { return a - b; } 24 | float multiply(const float& a, const float& b) override { return a * b; } 25 | float divide(const float& a, const float& b) override { return a / b; } 26 | }; 27 | 28 | int main() 29 | { 30 | ServiceLocator locator; 31 | 32 | //Single instance creation => everytime "resolve" gets called the same instance will be returned 33 | locator.registerInstance(new MathService()); 34 | 35 | auto mathService = locator.resolve(); 36 | assert(mathService); 37 | assert(mathService->add(10, 20) == 30); 38 | assert(mathService->subtract(30, 10) == 20); 39 | assert(mathService->multiply(2, 2.5) == 5); 40 | assert(mathService->divide(30, 10) == 3); 41 | 42 | //simple check if it's really the same instance 43 | auto test = std::static_pointer_cast(mathService); 44 | assert(test->state == 0); 45 | test->state = 1; 46 | test = std::static_pointer_cast(locator.resolve()); 47 | assert(test->state == 1); 48 | 49 | 50 | //explicit clear of all instances 51 | locator.clear(); 52 | //there should be no IMathService anymore 53 | mathService = locator.resolve(); 54 | assert(!mathService); 55 | 56 | 57 | //you can create lazy instances with a delegate which returns a shared ptr 58 | //the instance will be created everytime the "resolve" method gets called 59 | locator.registerCreator([]() { return std::make_shared(); }); 60 | 61 | mathService = locator.resolve(); 62 | assert(mathService); 63 | 64 | //same check as above but this time changing the state and resolving the service should return an other instance 65 | test = std::static_pointer_cast(mathService); 66 | assert(test->state == 0); 67 | test->state = 1; 68 | 69 | test = std::static_pointer_cast(locator.resolve()); 70 | assert(test->state == 0); 71 | 72 | return 0; 73 | } --------------------------------------------------------------------------------