{"id":16036271,"url":"https://github.com/ebellocchia/factories_injector","last_synced_at":"2025-04-10T06:08:39.828Z","repository":{"id":110358075,"uuid":"250089330","full_name":"ebellocchia/factories_injector","owner":"ebellocchia","description":"C++ Template-based abstract factories injector","archived":false,"fork":false,"pushed_at":"2024-02-09T21:33:06.000Z","size":56,"stargazers_count":2,"open_issues_count":0,"forks_count":5,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-10T06:08:35.179Z","etag":null,"topics":["abstract-factory","abstract-factory-pattern","cpp-library","cpp14","factories-injector"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ebellocchia.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-03-25T20:55:07.000Z","updated_at":"2023-08-09T21:42:20.000Z","dependencies_parsed_at":"2024-02-09T15:40:48.092Z","dependency_job_id":"49f4a4e4-1b55-442f-89ae-17d143dfae4d","html_url":"https://github.com/ebellocchia/factories_injector","commit_stats":{"total_commits":28,"total_committers":2,"mean_commits":14.0,"dds":0.3214285714285714,"last_synced_commit":"e1c50e1cf42b3f55ee1fef2d6af98b19663095fd"},"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ebellocchia%2Ffactories_injector","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ebellocchia%2Ffactories_injector/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ebellocchia%2Ffactories_injector/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ebellocchia%2Ffactories_injector/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ebellocchia","download_url":"https://codeload.github.com/ebellocchia/factories_injector/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248166925,"owners_count":21058481,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["abstract-factory","abstract-factory-pattern","cpp-library","cpp14","factories-injector"],"created_at":"2024-10-08T22:02:27.052Z","updated_at":"2025-04-10T06:08:39.785Z","avatar_url":"https://github.com/ebellocchia.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# C++ Factories injector\n\n| |\n|---|\n| [![GitHub License](https://img.shields.io/github/license/ebellocchia/factories_injector?label=License)](https://github.com/ebellocchia/factories_injector?tab=MIT-1-ov-file) |\n| [![Build \u0026 Test](https://github.com/ebellocchia/factories_injector/actions/workflows/built-test.yml/badge.svg)](https://github.com/ebellocchia/factories_injector/actions/workflows/built-test.yml) |\n| [![Codecov](https://img.shields.io/codecov/c/github/ebellocchia/factories_injector?label=Code%20Coverage)](https://codecov.io/gh/ebellocchia/factories_injector) [![Codacy grade](https://img.shields.io/codacy/grade/a9ba229090be499fb27380aabcbc635b?label=Codacy%20Grade)](https://app.codacy.com/gh/ebellocchia/factories_injector/dashboard?utm_source=gh\u0026utm_medium=referral\u0026utm_content=\u0026utm_campaign=Badge_grade) [![CodeFactor Grade](https://img.shields.io/codefactor/grade/github/ebellocchia/factories_injector?label=CodeFactor%20Grade)](https://www.codefactor.io/repository/github/ebellocchia/factories_injector) |\n| |\n\n## Introduction\n\nThis is a template-based utility library composed of just a couple of header files, hence it doesn't need to be compiled and linked.\\\nIt allows run-time injection of factories, making the code completely independent from specific factory types and only dependent on factory interfaces.\\\nIn this way, you can use a real factory producing real objects in the production code, while in the testing code you can dynamically inject a factory producing test objects (e.g. stubs or mocks) without modifying a single line.\\\nFor being injected by the library, the factories shall follow the [abstract factory pattern](https://en.wikipedia.org/wiki/Abstract_factory_pattern) and inherit from the *FactoryTraits* structure defined by the library.\n\n## Installation\n\nAs already said, you just have to include the header files. There is no dependency and nothing to compile, since the entire code is based on templates.\\\nThe code is compliant to C++14 standard, so you need a compiler supporting C++14.\n\nTo compile the example and the unit tests, just run:\n\n    cmake .\n    make\n\nIn the folder where the *CMakeLists.txt* file is located.\\\nA *bin* folder will be created inside with the compiled files.\n\n**NOTE:** for compiling unit tests, you need *googletest* to be installed.\n\n## Usage\n\nTo inject a factory, you have to create a factory interface (*abstract factory*) that inherits from the *FactoryTraits* structure, by specifying its type and the interface of the object to be created.\n\n**Example**\n\n    // Object interface\n    class IObj\n    {};\n\n    // Abstract factory for IObj\n    class IObjFactory : public factory_injector::FactoryTraits\u003cIObjFactory, IObj\u003e\n    {\n        public:\n            virtual ~IObjFactory(void) = default;\n\n            // tObjectPtr is defined by FactoryTraits as std::unique_ptr\u003cIObj\u003e\n            virtual tObjectPtr Create(/* Some parameters */) const = 0;\n    };\n\nThen you can create your real factory classes (*concrete factories*) inheriting from the abstract factory and creating real objects.\n\n**Example**\n\n    // A real object, used for production\n    class MyRealObj : public IObj\n    {};\n\n    // A test object, used for testing\n    class MyTestObj : public IObj\n    {};\n\n    // Another test object, used for some other types of tests\n    class AnotherTestObj : public IObj\n    {};\n\n    // Concrete factory producing MyRealObj\n    class MyRealObjFactory : public IObjFactory\n    {\n        public:\n            tObjectPtr Create(/* Some parameters */) const override\n            {\n                return std::make_unique\u003cMyRealObj\u003e(/* Some parameters */);\n            }\n    };\n\n    // Concrete factory producing MyTestObj\n    class MyTestObjFactory : public IObjFactory\n    {\n        public:\n            tObjectPtr Create(/* Some parameters */) const override\n            {\n                return std::make_unique\u003cMyTestObj\u003e(/* Some parameters */);\n            }\n    };\n\n    // Concrete factory producing AnotherTestObj\n    class AnotherTestObjFactory : public IObjFactory\n    {\n        public:\n            tObjectPtr Create(/* Some parameters */) const override\n            {\n                return std::make_unique\u003cAnotherTestObj\u003e(/* Some parameters */);\n            }\n    };\n\nFinally, you have to register the concrete factory you want to use with one of the following methods:\n- *FactoryInjector::RegisterFactory\u003cFactoryType\u003e()* will register the factory type only if not already registered, otherwise a *FactoryAlreadyRegisteredEx* exception is thrown\n- *FactoryInjector::OverwriteFactory\u003cFactoryType\u003e()* will register the factory type in any case, overwriting it if already registered\n\nTo get back a factory, you can use the *FactoryInjector::GetFactory\u003cFactoryType\u003e()* method. Here you can either specify the concrete or the abstract factory type, but it's suggested to use the abstract one so that the code is completely independent from concrete factories.\\\nIn case you try to get a factory type that is not registered, a *FactoryNotRegisteredEx* will be thrown.\n\n**Example**\n\n    // You can wrap the factory injector in a singleton to make it globally accessible, or pass it around the classes that need it\n    factory_injector::FactoryInjector fi;\n\n    // Register MyRealObjFactory. From now on, all the code now will use MyRealObjFactory when calling GetFactory, this producing MyRealObj\n    // OverwriteFactory can also be used here, it's the same\n    fi.RegisterFactory\u003cMyRealObjFactory\u003e();\n\n    //\n    // Somewhere else in the production code...\n    //\n\n    // Get the factory by the abstract type\n    // It will get MyRealObjFactory, MyTestObjFactory or AnotherTestObjFactory depending on what it's registered\n    auto\u0026 obj_factory = fi.GetFactory\u003cIObjFactory\u003e();\n    // Let's produce some object instances. MyRealObj, MyTestObj or AnotherTestObj will be produced depending on the registered factory.\n    // In this way, the code is independent from the concrete factory, which can be injected dynamically.\n    for (int i = 0; i \u003c 10; i++)\n    {\n        // obj is of type std::unique_ptr\u003cIObj\u003e\n        auto obj = obj_factory.Create(/* Some parameters */);\n        // Do something with the object\n    }\n\n    // Alternatively, there is a helper method called CreateObject. It simply calls internally the factory Create method, if defined.\n    // It's just a shortcut, if you a different name for the method or you need to use the factory multiple times (e.g. in a loop),\n    // just use the GetFactory as described previously\n    auto obj = fi.CreateObject\u003cIObjFactory\u003e(/* Some parameters */);\n\n    //\n    // In a test code, we need to use MyTestObj\n    //\n\n    // Register MyTestObjFactory (MyRealObjFactory will be overwritten if registered)\n    fi.OverwriteFactory\u003cMyTestObjFactory\u003e();\n    // Now, the previous code will use MyTestObj objects instead of MyRealObj\n\n    //\n    // In another test code, we need to use AnotherTestObj\n    //\n\n    // Register AnotherTestObjFactory\n    fi.OverwriteFactory\u003cAnotherTestObjFactory\u003e();\n    // Now, the previous code will use AnotherTestObj objects instead of MyRealObj\n\nOf course, you can register as many factory types as you want, as long as they inherit from a different interface.\n\n## How it works\n\nThe base concept is quite simple. The *FactoryInjector* class is keeping track of the registered types by means of a hash table.\\\nUsing the *FactoryTraits*, the class deducts the interface type of the concrete factory. Then, it creates an instance of the concrete factory and inserts it in the hash table, associating it with the *typeid* of the abstract factory. Therefore, if you register another concrete factory inheriting from the same abstract factory, it will overwrite the existent one because the *typeid* of the abstract factory is always the same and it is used as a key of the hash table.\\\nWhen you get a factory, a reference to the concrete instance is simply returned by searching for the *typeid* of the abstract factory in the hash table.\\\nThe library takes advantage of move semantics, perfect forwarding and variadic templates to be as most generic as possible.\n\n## License\n\nThis software is available under the MIT license.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Febellocchia%2Ffactories_injector","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Febellocchia%2Ffactories_injector","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Febellocchia%2Ffactories_injector/lists"}