Delegation design patterns applied in mobile solutions

Delegation design patterns applied in mobile solutions


 Context

Delegation is a mechanism used in solutions to provide extensibility and flexibility to designs. These characteristics are essential so that the designed components comply with a quality attribute known as maintainability.

Maintainability is an attribute valued in applications as it is an indicator of the ability of a piece of software to change over time without significantly impacting the current design and maintaining its consistent operation.

It is a daily task in a project to modify and update components to add new functionality or capacity.

It is a great advantage when the component is designed with maintainability since there will be less effort and the impact required to extend its responsibilities and capabilities. That brings benefits for the solution, the project, and the team.

And how do you provide and achieve the desired maintainability in the components?

We can use delegation mechanisms.

Delegation can be applied through different design patterns and strategies. This article will focus on the ones commonly needed in mobile solutions.

There are functional programming languages such as Swift and Kotlin for iOS and Android, respectively.

These modern languages introduce functional aspects from their base, combining different paradigms and implementations with functional, reactive, and imperative programming.

The strategies and design patterns described in this article are not new. Indeed, they are part of the set of base patterns described in the book Design Patterns — Elements of Reusable Object-Oriented Software (by GoF), a tool key in software development for a long time.

We can currently implement these patterns using these functional languages to save repetitive code. Additionally, these languages promote delegation by preferring aggregation and composition rather than inheritance, which significantly benefits the design.

The first strategy that I am going to describe to apply delegation is the use of the Decorator pattern, but first, I must clarify the following keyword:

Software piece: Refers to a class, structure, enum, object, or any dependency external or internal to the project.

Decorator

Use case: We have a software piece to which we want to extend its functionalities without modifying the original piece. Additionally, you want to avoid inheriting unnecessary dependencies.

This pattern allows you to extend the responsibilities of a component without modifying its base definition. Whether it is an external component (from a third party) or an internal component of our implementation, we could adjust with more outstanding capabilities without modifying the component’s implementation.

Implementation: In both Swift and Kotlin, you can use the extension functions concept to implement this pattern like so:

iOS example

Results in the console:

Executed base operation in BaseComponent

Executed an extra operation for BaseComponent 🚀

30.25

Android example

Results in the console:

Executed base operation in BaseComponent

Executed an extra operation for BaseComponent 🚀

30.25

The delegation, in this case, is done by aggregation and not by inheritance, which is better in most cases.

Adapter

Use case: We have a software piece that we want to adjust to comply with a specific contract without modifying the original piece. In such a way, the adjustment allows the piece of software to be integrated into the desired structure.

This pattern allows, through extension, to incorporate a change to the component to adjusting it to the desired structure without modifying the base component’s structure.

Implementation: In Swift, protocol extension is used to implement this pattern. In Kotlin, class delegation is used via extension functions + interfaces like so:

iOS example

Results in the console:

The base operation in LegacyComponent has been adapted


Android example

Results in the console:

The base operation in LegacyComponent has been adapted


Kotlin also provides another type of delegation for cases where the same interface is formed; an example of this strategy using the “by” keyword will be shown later.

The Decorator and Adapter patterns seem to be similar forms of delegation. Still, they differ mainly because the Decorator seeks to extend the capabilities without intending to change the structure or the contract that the component fulfills.

In contrast, the Adapter aims to extend the component to that assumes a structure that makes it compatible with a given contract.

Strategy

Use case: We have a software piece that needs to be endowed with extra capabilities with different types of behavior (logic).

The purpose of the Strategy Pattern is to extend the behavior of the component (logic) rather than its form, which is why it is classified as a Behavioral Pattern.

While the previous patterns, Decorator and Adapter, are classified as Structural Patterns. I like the phrase with which they refer to this fact in Design Patterns — Elements of Reusable Object-Oriented Software (by GoF):

“A decorator lets you change the skin of an object; a strategy lets you change the guts. These are two alternative ways of changing an object”.

Implementation: In Swift, we can implement this pattern through protocols. In Kotlin, delegation is natural and built-in by default via the “by” keyword as shown below:

iOS example

Results in the console:

Operation executed by StrategyOne for ClientUsingStrategy

Operation executed by StrategyTwo for ClientUsingStrategy


Android example

Results in the console:

Operation executed by StrategyOne for ClientUsingStrategy

Operation executed by StrategyTwo for ClientUsingStrategy


Finally, I will describe another strategy that, in my opinion, more than another pattern, is the application of the simplified Strategy Pattern, that is, when only one strategy option is applied.

This mechanism is known as Delegate and is another form of Delegation.


Delegate

iOS example

Results in the console:

Operation delegated to Manager for the ClientUsingDelegate


Android example

Results in the console:

Operation delegated to Manager for the ClientUsingDelegate


Conclusions

Of course, on mobile, we can use many other design patterns. In this article, I have focused on those that provide Delegation.

These patterns can be applied in different layers and types of artifacts; that is, they could be applied in Repositories, ViewModels, Uses Cases, DataSources, or any other component.

I have also wanted to show an alternative way of implementing them different from the usual imperative form, this thanks to the advantages offered by modern languages such as Swift and Kotlin.


Next
This is the current newest page
Previous
Next Post »
Thanks for your comment