Exploring Structural Design Patterns

With Real World Examples | Part 2 | Day 6 of #100DaysOfCode

Dhananjay Trivedi
5 min readSep 23, 2019

We will continue our journey of exploring the Structural Design Pattern of Day 5. We explored Adapter, Bridge, Composite pattern. If you haven’t read it yet, please do before we move on to other patterns here.

4. Decorator Pattern

Real-world example — We decorate ourselves with clothes to protect ourselves against bad weather. For example, if its cold we put on a sweater, if we still feel cold we put on a Jacket. If it’s raining, then we might put on a rain-coat. You can remove these garments when the job is done. Here, you are extending the features of those garments as you require which aren’t a part of you.

Similarly, we attach/decorate some existing objects with some new functionalities using the Wrapper objects that contain that behavior.

We generally use Inheritance to get some parent class behavior. Inheritance would be like you stitching some sweater permanently with your body (don’t even imagine!). Inheritance in classes can lead to a few problems like

  • Code Bloating: You will be creating a lot of classes extending your parent class to achieve some functionality.
  • Inheritance is static: You cant change the behavior of an existing object at runtime, you can only replace the whole object.

Child classes generally can have only one parent class, most programming languages don’t support Multiple Inheritance.

Technical Example — While building a notification hub, you might have various classes to notify users through SMS, Facebook, Slack, Email etc. Each of these will be extending some common ‘Notifier Class’. Things will be working smooth as you have to send each specific notification. Now in case, you want to send a notification through all of them, or with a combination of them. You will have to either extend all the classes, or you will have to create instances of each of these notifications, both are quite ugly approaches as it will lead to a lot of bloated code.

Hence, with the composition pattern, you can compose your objects to behave in a certain way which can be changed at the runtime through delegating various wrapper classes. Your objects can implement a common interface just like we do in composition pattern which helps you achieve that common functionality without changing/getting into the concrete class implementation.

5. Facade Pattern

Real-world example, there is a business that looking to get a website built. It hires an agency to get the job done. But what if the client here has to deal with all the designers, front end developers, back end developers. Doesn’t sound very convenient for the client as its shouldn’t be the client’s responsibility. Hence there are project managers, that act as an intermediator between the devs and the client by understanding the client’s requirements and gets the specific job done.

Similarly, when your project gets complex where it is dealing with a lot of objects, methods being called in a certain order, manage all the dependencies and runtime checks. The business logic here is getting tightly coupled with the implementation details.

Hence we require a simple interface that the business logic needs to communicate to for getting the work done from complex implementation. But be sure that your facade class doesn’t become a god class which itself gets tightly coupled with multiple classes (This situation might be hard to avoid) while you are trying to abstract the complexity of implementation, which is a good thing.

6. Flyweight Pattern

Real-world example, imagine a shooting game like Counter-Strike where players are shooting bullets all over the map. You are asked to write the bullet class where there is coordinates, vector, speed, color, sprite and has certain methods like move() and draw().

If you will run such a program and shoot hundreds of bullets, each bullet will have its own object in the memory and heavy properties like color and sprite will take up a lot of memory. Imagine for all the players you have hundreds of objects of bullets for each player. You are sure your game is going to run out of memory.

Hence, we can reduce the memory consumption by structuring the code in some way that these values which are common for a lot of objects can be shared by all without consuming much memory.

Intrinsic Properties — The constant properties stored within the objects which can only be read by other objects.

Extrinsic Properties — The variables stored within the objects which can be changed by other objects.

Flyweight Patterns suggests that you stop storing the extrinsic state inside the object, we should only pass these state to specific methods which rely on it. Only the intrinsic state stays within the object. An object that stores only instrisic properties is called Flyweight object.

An elegant solution now is to create a separate context class that would store the extrinsic state along with reference to the flyweight objects. Hence maybe a game class that deals with bullets. The number of bullets fired will still be the same but now these objects are much more light-weight (as we have separated Extrinsic and Intrinsic properties) and that was the main problem we just solved.

7. Proxy Pattern

Real-world example, Nowadays you don’t have to keep cash with you all the time. For making any amount of payment. Just imagine how much big of a problem it would be if you had to have the cash reserves with you all the time. Unnecessary things you will have to manage. Instead, you have a bank that provides you with a Credit card that acts as a proxy for your cash reserves and you request them to give you access to make the payments only when it’s required and they perfectly do that job.

Similarly, Imagine if there are multiple objects which are connecting to the database and consuming it. You don’t want them to be connected all the time and hence you will write lazy instantiation where you initialize them to connect with DB only when it’s required. But this will lead to a lot of redundant code across all these classes which can be avoided using Proxy Pattern.

Hence, instead of allowing your objects to access DB directly, you create a ‘Proxy’ class to handle the requests and allow them to consume the service resources only when the request comes from the client object. You don’t have to change anything on the client-side, and neither on the service side. The proxy pattern is where you add your logic to keep things working smoothly.

You can control the service objects without clients knowing about it. You can manage the service lifecycle without your clients caring about it. You can add more proxies as required following the open-closed principle, although there might be a slight delay in response from the server.

That’s all for Day 6. Have a good one!

--

--

Dhananjay Trivedi
Dhananjay Trivedi

Written by Dhananjay Trivedi

Android | Flutter | App Developer | Product Management | Prompt Engineer who loves writing and sharing knowledge

No responses yet