Group 12 - Behavioral Pattern

Behavioral design patterns are design patterns used in software engineering to recognize and realize common communication patterns between objects. These patterns increase the flexibility with which this communication can be carried out as a result of this.

The interaction and responsibility of objects are addressed by behavioral design patterns.

The interaction between the objects in these design patterns should be loosely coupled while still allowing them to easily communicate with one another.

In order to avoid hard coding and dependencies, the implementation and client should be loosely coupled.

Source : coursehero.com

Let's have a look at each of them

Chain of Responsibility Pattern


Intent

A behavioural design pattern called Chain of Responsibility allows you to pass requests along a chain of handlers. When a request arrives, each handler decides whether to process it or forward it to the next in the chain.

Source : refracting.guru

Problem

Assume you're working on a web-based ordering system. You wish to limit system access so that only authorised users can place orders. Users with administrative privileges must also have complete access to all orders.

After a little forethought, you discovered that these checks must be carried out in a specific order. When the programme receives a request containing the user's credentials, it might attempt to authenticate the user to the system. If the credentials are incorrect and authentication fails, there's no need to perform any additional tests.

Source : refracting.guru

Several more of those consecutive checks were implemented over the next few months.

  • One of your coworkers argued that sending raw data to the ordering system is risky. So, to sanitise the data in a request, you introduced an extra validation step.

  • Someone later discovered that the system is susceptible to brute force password cracking. You quickly included a check that filters repeated unsuccessful requests from the same IP address to counteract this.

  • Someone else suggested caching responses for repeated requests with the same data to speed up the system. As a result, you implemented another check that allows the request to go to the system only if no sufficient cached response exists.


Source : refracting.guru

As you introduced each new feature, the checks' code, which was already a shambles, became even more bloated. Changing one check could have an impact on the others. Worse, when you tried to reuse the checks to protect other system components, you had to duplicate some of the code because those components only needed a portion of the tests.

The system became extremely difficult to understand and manage. You wrestled with the code for a while before deciding to refactor it all at once.


Solution

The Chain of Responsibility, like many other behavioural design patterns, relies on the transformation of specific behaviours into stand-alone objects known as handlers. Each check should be removed to its own class with a single method to perform the check in our scenario. This method receives the request as an argument, along with its data.

The pattern proposes forming a chain with these handlers. A field in each linked handler stores a reference to the next handler in the chain. Handlers not only process requests, but they also transmit them along the chain. The request is passed down the chain until it has been processed by all handlers.

The finest feature is that a handler can choose not to forward the request farther down the chain, thereby stopping all processing.

In our ordering system example, a handler does the processing before deciding whether or not to forward the request farther down the chain. All handlers can perform their primary activity, whether it's authentication checks or caching, as long as the request provides the correct data.

Source : refracting.guru

However, there is a somewhat different (and more traditional) technique in which a handler evaluates whether it can process a request after receiving it. It doesn't pass the request any further if it can. As a result, the request is processed by either one handler or none at all. When dealing with events in stacks of items within a graphical user interface, this approach is quite frequent.

When a user presses a button, for example, the event propagates via a chain of GUI components that begins with the button and continues through its containers (such as forms or panels) to the main programme window. The first unit in the chain capable of handling the event processes it. This example is especially interesting since it demonstrates that an object tree can always be used to extract a chain.

Source : refracting.guru

The implementation of the same interface by all handler classes is critical. Each concrete handler should only be concerned with the execute method of the one after it. This allows you to create chains at runtime by combining different handlers without having to worry about attaching your code to their concrete classes.

Pros

  • You have control over the sequence in which requests are handled.

  • Principle of a single point of responsibility. Classes that invoke operations and classes that conduct operations can be separated.

  • The Open/Closed Principle is a concept that describes how anything might be open or closed. Without affecting the existing client code, you can add additional handlers to the app.

  • Some requests may go unanswered.



Command Pattern

Intent

A behavioural design pattern that turns a request into a stand-alone object with all of the request's details is known as a command. This transformation enables you to pass requests as to method arguments, delay or queue the request's execution, and provide undoable operations.

Source : refracting.guru

Problem

Assume you're developing a new text editor app. Your current objective is to design a toolbar with a variety of buttons for the editor's various tasks. You've designed a fantastic Button class that can be used for toolbar buttons as well as generic buttons in various dialogues.

While all of these buttons appear to accomplish the same thing, they're all supposed to do something different. Where would you put the code for these buttons' various click handlers? The most straightforward answer is to create a large number of subclasses for each location where the button is utilised. These subclasses would hold the code that would be performed when a button was pressed.

Before long, you realize that this approach is deeply flawed. First, you have an enormous number of subclasses, and that would be okay if you weren’t risking breaking the code in these subclasses each time you modify the base Button class. Put simply, your GUI code has become awkwardly dependent on the volatile code of the business logic.

Source : refracting.guru

Then there's the portion that's the most revolting. Some tasks, such as copying and pasting text, would need numerous calls. A user may, for example, click a little "Copy" button on the toolbar, copy something from the context menu, or simply press Ctrl+C on the keyboard to copy something.

It was OK to place the implementation of numerous operations inside the button subclasses when our programme simply had the toolbar. To put it another way, the function for copying text was fine inside the CopyButton subclass. However, as you add context menus, shortcuts, and other features, you'll either have to repeat the operation's code across many classes or make menus reliant on buttons, which is an even worse alternative.

Solution

The separation of concerns idea is often used in software design, which leads to the division of an app into layers. A layer for the graphical user interface and another for the business logic is the most popular example. The GUI layer is responsible for creating a pleasing image on the screen, capturing any input, and displaying the results of the user's and app's actions. When it comes to crucial tasks, such as calculating the moon's trajectory or writing an annual report, the GUI layer delegates the job to the underlying layer of business logic.

It might look like this in the code: A GUI object calls the method of a business logic object and passes it some arguments. This is commonly depicted as one thing requesting something from another.

Source : refracting.guru

The next step is to ensure that all of your commands have the same interface. It usually only has one execution method that accepts no parameters. This interface lets you use various commands with the same request sender, without coupling it to concrete classes of commands. You can now switch command objects linked to the sender as a bonus, effectively changing the behaviour of the sender at runtime.

One missing piece of the puzzle, the request parameters, may have caught your attention. The business-layer object could have received some parameters from a GUI object. How would we pass the request details to the receiver since the command execution method doesn't have any parameters? It turns out that the command should either have this data pre-configured or be able to obtain it on its own.

Source : refracting.guru

Let's return to our text editor for a moment. We don't need all those button subclasses to create distinct click actions after we apply the Command pattern. It's simple to add a single field to the base Button class that contains a reference to a command object and have the button run that action when the button is clicked.

You'll create a set of command classes for each potential operation and link them to certain buttons based on the intended behaviour of the buttons.

Menus, shortcuts, and whole dialogues, for example, can all be built in the same way. They'll be linked to a command that'll be run whenever a user interacts with a GUI element. As you may expect, items that are related to the same operations will be linked to the same commands, preventing code duplication.

As a result, commands serve as a useful intermediary layer between the GUI and the business logic levels, reducing coupling. And that's only a small part of what the Command pattern has to offer!

Pros

  • Principle of a single point of responsibility. Classes that invoke operations and classes that perform these operations can be separated.

  • The Open/Closed Principle is a concept that describes how anything might be open or closed. New commands can be added to the app without disrupting existing client code.

  • You can use the undo/redo feature.

  • Deferred execution of operations is something you can do.

  • You can make a complex command out of a sequence of simple instructions.

Cons

  • Because you're adding a new layer between senders and receivers, the code could get a little more difficult.

Iterator Pattern

Intent

Iterator is a behavioural design pattern that allows you to traverse components of a collection without revealing the representation below (list, stack, tree, etc.).

Source : refracting.guru

Problem

In programming, collections are one of the most commonly used data types.

A collection, on the other hand, is nothing more than a container for a bunch of objects. The elements of most collections are stored in simple lists. Stacks, trees, graphs, and other sophisticated data structures are used in some of them.

However, regardless of how a collection is organized, it must give some means of accessing its elements so that other code can use them. There should be a way to traverse through each collection element without having to access the same ones over and over.

Source : refracting.guru

If you have a list-based collection, this may appear to be a simple task. All you have to do is loop through all of the elements. But how can you visit parts of a large data structure like a tree in a sequential manner? For example, you might be quite fine traversing a tree depth-first one day. The next day, though, you might need to do a breadth-first traverse. You might require something else the following week, such as random access to tree elements.

Source : refracting.guru

The collection's fundamental responsibility, efficient data storage, becomes increasingly muddled when more traversal algorithms are added. Furthermore, some algorithms may be tuned for a specific purpose, making their inclusion in a generic collection class strange.

Client code that is designed to work with diverse collections, on the other hand, may not care how their elements are stored. You have no choice but to couple your code to the specific collection classes because collections all provide distinct ways of accessing their elements.

Solution

The Iterator pattern's core notion is to split a collection's traversal functionality into a distinct object called an iterator

An iterator object incorporates all traversal details, such as the current location and how many elements remain till the end, in addition to implementing the algorithm itself. As a result, multiple iterators can work on the same collection at the same time, independently of one another.

Iterators usually have only one principal technique for retrieving elements from a collection. The client can keep calling this method until it returns null, which indicates that the iterator has reached the end of the list of elements.

The same interface must be implemented by all iterators. As long as there is a correct iterator, the client code is compatible with any collection type or traversal strategy. You can construct a new iterator class without changing the collection or the client if you require a unique way to traverse a collection.

Pros

  • Principle of a single point of responsibility. Bulky traversal algorithms can be separated into different classes to clean up the client code and collections.

  • The Open/Closed Principle is a concept that describes how anything might be open or closed. Without disrupting anything, you can create new types of collections and iterators and pass them to existing code.

  • Because each iterator object has its own iteration state, you can iterate over the same collection concurrently.

  • For the same reason, you can put off an iteration and resume it later.


Cons

  • If your software only works with simple collections, applying the pattern may be overkill.

  • Iterating through elements of some specialized collections directly may be more efficient than using an iterator.

Mediator Pattern

Intent

The mediator is a behavioural design pattern that allows you to eliminate the chaos of object dependencies. The pattern prevents the items from communicating directly with one other, forcing them to collaborate only through a mediator object.

Source : refracting.guru

Problem

Assume you're having a conversation about building and modifying client profiles. Text fields, checkboxes, buttons, and other form controls are included. Some form elements might interact with one another. Selecting the "I have a dog" checkbox, for example, may disclose a secret text field where you can enter the dog's name. Another example is the submit button, which must validate all fields' contents before saving the information.

Because this logic is written directly in the code of the form components, it is much more difficult to reuse the classes of these elements in other parts of the programme. Because the checkbox class is linked to the dog's text field, you won't be able to use it in another form. You can utilise all or none of the classes involved in rendering the profile form.

Solution

You should stop all direct contact between the components you want to be independent of one another, according to the Mediator pattern. Instead, these components must work together through a special mediator object, which directs calls to the appropriate components. As a result, instead of being linked to hundreds of coworkers, the components are only reliant on a single mediator class.

The dialogue class itself may act as the mediator in our profile editing form example. You won't need to add any new dependencies to the dialogue class because it is likely already aware of all of its sub-elements.

Source : refracting.guru

The actual form elements undergo the most significant change. Let's take a look at the submit button. Previously, each time a user clicked the button, the values of all individual form elements had to be validated. Its sole purpose now is to alert the dialogue to the click. The dialogue performs the validations or passes the task to the individual elements after receiving this notification. As a result, the button is only dependent on the dialogue class, rather than a dozen form elements.

By extracting the common interface for all types of dialogues, you can loosen the dependency even more. The notification method would be declared in the interface, and all form elements would be able to use it to notify the dialogue about events that occurred to those elements. As a result, any dialogue that implements that interface should now be able to use our submit button.

The Mediator pattern allows you to encapsulate a complex web of relationships between different objects in a single mediator object in this way. The fewer dependencies a class has, the more easily it can be modified, extended, or reused.

Pros

  • Single Responsibility Principle. You can extract the communications between various components into a single place, making it easier to comprehend and maintain.

  • Open/Closed Principle. You don't have to change the actual components to introduce new mediators.

  • You can make a program's various components less intertwined.

  • You can reuse individual components more easily.

Cons


Memento Pattern

(Also known as Snapshot)

Intent

Memento is a behavioural design pattern that allows you to save and restore an object's previous state without revealing the implementation details.

Problem

Assume you're working on a text editor app. Your editor can format text, insert inline images, and more, in addition to simple text editing. You decided at some point to allow users to undo any text manipulations. This feature has become so common over the years that people now expect it in every app. You chose to take a direct approach to implementation. The app records the state of all objects and saves it in some storage before performing any operation. When a user later wants to undo an action, the app retrieves the most recent snapshot from the history and restores the state of all objects.

Source : refracting.guru

Consider those state snapshots for a moment. How would you go about making one? You'd probably have to go through an object's fields and copy its values into storage. However, this would only work if the object's content had very loose access restrictions. Unfortunately, most real objects don't make it easy for others to look inside them, hiding all important data in private fields.

For the time being, ignore that issue and assume that our objects act like hippies, preferring open relationships and keeping their status public. While this approach would solve the immediate problem by allowing you to create snapshots of object states whenever you want, it still has some serious flaws. You might want to refactor some of the editor classes in the future, or add or remove some of the fields. Although this appears to be a simple task, it would necessitate changing the classes responsible for copying the state of the affected objects.

Source : refracting.guru

There's more, though. Consider the "snapshots" of the editor's current state. What information is contained within it? It must at the very least include the actual text, cursor coordinates, current scroll position, and so on. To create a snapshot, you'd need to gather these values and store them in a container.

Most likely, you'll store a large number of these container objects in a list that represents the history. As a result, the containers are most likely to be objects of the same class. There would be almost no methods in the class, but there would be a lot of fields that mirrored the editor's state. You'd probably have to take a snapshot's fields public to allow other objects to write and read data to and from it. That would reveal all of the editor's private and public states. Other classes would become reliant on every change to the snapshot class, which would otherwise occur only in private fields and methods, affecting only the snapshot class.

We appear to have come to a stalemate: either expose all internal details of classes, making them too fragile or restrict access to their state, making snapshots impossible. Is there any other way to use the "undo" feature?

Solution

All of the issues we've just discussed are due to a lack of encapsulation. Some objects try to accomplish more than they should. Instead of letting these objects perform the actual action, they invade the private space of other objects to collect the data needed to perform that action.

The Memento pattern delegated the creation of state snapshots to the originator object, which is the actual owner of that state. As a result, rather than other objects attempting to copy the editor's state from the "outside," the editor class can take a snapshot of its own state because it has full access to it.

The pattern recommends storing a copy of the object's state in a special memento object. Any object other than the one that created the memento has no access to its contents. Other objects must communicate with mementoes through a limited interface that allows them to retrieve the snapshot's metadata (creation time, name of the performed operation, etc.) but not the original object's state.

Source : refracting.guru

The originator has full access to the memento, whereas the caretaker can only access the metadata.

With such a strict policy in place, you can store mementoes inside other objects known as caretakers. Because the caretaker can only interact with the memento through a limited interface, it is unable to alter the state stored within it. At the same time, the creator has complete control over all fields within the memento, allowing it to revert to its original state at any time.

We can create a separate history class to act as the caretaker in our text editor example. Each time the editor is about to perform an operation, a stack of mementoes stored inside the caretaker will grow. You could even display the history of previously performed operations to a user by rendering this stack within the app's UI.

When a user requests a rollback, the history grabs the most recent memento from the stack and sends it back to the editor. Because the editor has complete access to the memento, it modifies its own state using data from the memento.

Pros

  • Without breaking the object's encapsulation, you can take snapshots of its state.

  • You can make the originator's code simpler by allowing the caretaker to keep track of the originator's state history.

Cons

  • If clients create mementoes too frequently, the app may consume a lot of RAM.

  • To be able to destroy obsolete mementoes, caretakers should keep track of the originator's lifecycle.

  • Most dynamic programming languages, such as PHP, Python, and JavaScript, cannot ensure that the state of the memento remains unchanged.


Observer Pattern

(Also known as Event-Subscriber, Listener)

Intent

The observer design pattern allows you to specify a subscription mechanism for multiple objects to be notified of any events that occur on the object they're watching.

Problem

Consider the following scenario: you have a Customer and a Store. The customer is very interested in a specific brand of product (for example, a new iPhone model) that will be available in the store very soon.

Every day, the customer could come into the store to check product availability. However, most of these trips would be pointless while the product is still on its way.

Source : refracting.guru

On the other hand, when a new product is available, the store could send out a flood of emails (which could be considered spam) to all customers. This would save some customers the trouble of making multiple trips to the store. At the same time, it would irritate customers who aren't interested in trying new things.

There appears to be a problem. Either the customer wastes time checking availability or the store wastes resources notifying the incorrect customers.

Solution

The object that has an interesting state is commonly referred to as the subject, but because it will also notify other objects about the changes to its state, we'll refer to it as the publisher. Subscribers are all other objects that want to keep track of changes to the publisher's state.

According to the Observer pattern, the publisher class should have a subscription mechanism so that individual objects can subscribe to or unsubscribe from a stream of events coming from that publisher. Don't be concerned! Everything isn't as difficult as it appears. In reality, this mechanism consists of two parts: 1) an array field for storing a list of subscriber object references, and 2) several public methods for adding and removing subscribers from that list.

Source : refracting.guru

When the publisher encounters a significant event, it now goes through its subscribers and invokes the appropriate notification method on each of their objects.

In real apps, there could be dozens of different subscriber classes interested in tracking the same publisher class's events. You don't want to link the publisher to every single one of those classes. Furthermore, if your publisher class is intended to be used by others, you may not be aware of some of them beforehand.

As a result, it's critical that all subscribers use the same interface and that the publisher only communicates with them through it. This interface should declare the notification method as well as a set of parameters that the publisher can use to include some contextual data in the notification.

Source : refracting.guru

If your app has multiple types of publishers and you want your subscribers to be able to use them all, you can take it a step further and make all publishers use the same interface. Only a few subscription methods would need to be described in this interface. Subscribers would be able to observe the states of publishers without having to know their concrete classes.

Pros

  • Principle of open/closed. You can add new subscriber classes to the publisher's code without changing it (or vice versa if the publisher has an interface).

  • At runtime, you can create relationships between objects.

Cons

  • The order in which subscribers are notified is determined at random.