As opposed to using factory member functions, we can also implement them using non-member ones. This way, we can provide better encapsulation, as described by Scott Meyers in his article linked in the Further reading section.
In the case of our Pixel, we could also create a free function to fabricate its instances. This way, our type could have simpler code:
struct Pixel { char r, g, b, a; }; Pixel makePixelFromRgba(char r, char b, char g, char a) { return Pixel{r, g, b, a}; } Pixel makePixelFromBgra(char b, char g, char r, char a) { return Pixel{r, g, b, a}; }
Using this approach makes our design conform to the open-closed principle described in Chapter 1, Importance of Software Architecture and Principles of Great Design. It's easy to add more factory functions for other color palettes without the need to modify the Pixel struct itself.
This implementation of Pixel allows the user to initialize it by hand instead of using one of our provided...