Design Patterns =============== CRTP / Mixins -------------- `Article by fluentcpp.com on CRTP `_ * Mixins are a design pattern used to add additional functionality to an existing class * In this case, the ``TargetInfo`` and the ``Target`` class are meant to have a lot of setter APIs for user inputs. * Adding more APIs to the class makes its difficult to read and maintain. * For reference: See :doc:`serialization_schema` * For example: In Target ``source_files`` have currently have several APIs * ``AddSource`` * ``AddSourceAbsolute`` * ``GlobSources`` * ``GlobSourcesAbsolute`` * In the future we might have additional APIs such as * ``AddSources`` that takes an ``std::initializer_list`` * ``AddSources`` that takes a ``std::vector<>`` or ``std::unordered_set<>`` * ``AddSource(s)ByPattern`` that takes a fmt string like ``{dir}/source.cpp`` * From our serialization schema we can see that each of these fields could have many APIs associated with them. Having 50+ APIs for different fields in a single header i.e ``target_info.h`` / ``target.h`` would not be readible and hard to maintain. * The Mixin / CRTP pattern is used to easily add functionality for a particular field in its own header / source file. Friend classes --------------- * Friend classes are used when 2 classes have strong coupling with each other, but still need to maintain flexibility for other purposes. For example: Unit testing. * In ``target.h`` we have 3 friend classes (non CRTP based) * ``CompilePch`` * ``CompileObject`` * ``LinkTarget`` * These 3 classes are made friend classes for 2 main purposes * Unit Testing * Flexibility / Maintaibility * Unit Testing * If these were not friend classes, the functions would've been private in scope within the ``Target`` class * Unit testing these individual private functions would not be possible would public interfaces * By making them friend classes, We can now unit test the public functions and embed this class in a private context with the ``Target`` class * Flexibility / Maintaibility * Each one of the classes mentioned above have their own information / states / tasks to hold. * Without this segregation all of the member variables, states and tasks would need to be present inside the ``Target`` class * Strong Coupling * The 3 friend classes have strong coupling with the ``Target`` class since it uses its internal member variables for setting / getting information. * The friend class can interact with the parent class and vice versa.