The Façade pattern is handy for simplifying consumers’ lives, allowing us to hide subsystems’ implementation details behind a wall. There are multiple flavors to it; the two most prominent ones are:
- The transparent façade, which increases flexibility by exposing at least part of the subsystem(s)
- The opaque façade, which controls access by hiding most of the subsystem(s)
Now, let’s see how the transparent façade pattern can help us follow the SOLID principles:
- S: A well-designed transparent façade serves this exact purpose by providing a cohesive set of functionalities to its consumers by hiding overly complex subsystems or internal implementation details.
- O: A well-designed transparent façade and its underlying subsystem’s components can be extended without direct modification, as we saw in the Flexibility in action section.
- L: N/A
- I: By exposing a façade that uses different smaller objects implementing small interfaces, we could say that the segregation is done at both the façade and the component levels.
- D: The Façade pattern does not specify anything about interfaces, so it is up to the developers to enforce this principle by using other patterns, principles, and best practices.
Finally, let’s see how the opaque façade pattern can help us follow the SOLID principles:
- S: A well-designed opaque façade serves this exact purpose by providing a cohesive set of functionalities to its clients by hiding overly complex subsystems or internal implementation details.
- O: By hiding the subsystem, the opaque façade limits our ability to extend it. However, we could implement a hybrid façade to help with that.
- L: N/A
- I: The opaque façade does not help nor diminish our ability to apply the ISP.
- D: The Façade pattern does not specify anything about interfaces, so it is up to the developers to enforce this principle by using other patterns, principles, and best practices.
Summary
In this chapter, we covered multiple fundamental GoF structural design patterns. They help us extend our systems from the outside without modifying the actual classes, leading to a higher degree of cohesion by composing our object graph dynamically.We started with the Decorator pattern, a powerful tool that allows us to dynamically add new functionality to an object without altering its original code. Decorators can also be chained, allowing even greater flexibility (decorating other decorators). We learned that this pattern adheres to the Open-Closed principle and promotes the separation of responsibilities into smaller, manageable pieces.We also used an open-source tool named Scrutor that simplifies the decorator pattern usage by extending the built-in ASP.NET Core dependency injection system. Then, we covered the Composite pattern, which allows us to create complex, non-linear, and self-managed data structures with minimal effort. That hierarchical data structure where groups and single components are indistinguishable makes the hierarchy’s traversal and manipulation easier. We use this pattern to build graphs or trees with self-managing nodes.After that, we covered the Adapter pattern, which allows two incompatible interfaces to work together without modifying their code. This pattern is very helpful when we need to adapt the components of external systems that we have no control over, do not want to change, or can’t change.Finally, we dug into the Façade pattern, similar to the Adapter pattern, but at the subsystem level. It allows us to create a wall in front of one or more subsystems, simplifying its usage. It could also be used to hide the implementation details of a subsystem from its consumers.The next chapter explores two GoF behavioral design patterns: the Template method and the Chain of Responsibility design pattern.