Design Patterns in iOS — Adapter

Adapter Pattern Adapter Pattern: Converts the interface of a class into another interface that clients expect. The Adapter pattern lets classes work together that otherwise could not because of incompatible interfaces. An adapter is used to connect two different kinds of objects so they can work together seamlessly. It is sometimes called a Wrapper. The idea is straightforward: an adapter implements the behavior of some interface that the client understands, while also connecting to another object that has a completely different interface and behavior. On one side is the target interface that the client knows how to use; on the other side is the adaptee that the client knows nothing about. The adapter sits in between, and its main role is to pass the adaptee's behavior through to the client on the other end of the pipe. Class Diagram There are essentially two ways to implement an adapter. The first approach adapts two interfaces through inheritance and is called a Class Adapter. In C++, a class adapter is implemented via multiple inheritance. In languages like Java and Objective-C that do not support multiple inheritance, you can implement a class adapter by conforming to an interface or protocol while also subclassing a parent class. Specifically in Objective-C, you first need a protocol that defines the set of behaviors the client wants to use, and then you create a concrete adapter that implements this protocol. The adapter class must also inherit from the adaptee. refers to the target interface. refers to the class being adapted. refers to the request method. is both a type and an type. overrides 's method, but does not override 's method. Instead, inside 's implementation, it calls the parent class's method. At runtime, the method sends to the parent. is the , which executes in its own way within the scope of 's method. A class adapter in Objective-C can only be implemented when is a protocol rather than a class. The second approach is called an Object Adapter. Unlike the class adapter, an object adapter does not inherit from the adaptee — instead, it holds a reference to it through composition. When implemented as an object adapter, the relationships are: The relationship between and remains the same as in the class adapter, while the relationship between and changes from "is-a" to "has-a". In this setup, needs to maintain a reference to . Inside the method, sends to the referenced to indirectly access its behavior, then implements the remainder of the client's request. Because has a "has-a" relationship with , using to adapt subclasses of is also perfectly fine. Class Adapter vs. Object Adapter Class adapters and object adapters are different ways to implement the Adapter pattern but achieve the same goal. | Class Adapter | Object Adapter | |---|---| | Works only with a single concrete class,<br>adapting to | Can adapt multiple classes and their subclasses | | Easy to override 's behavior, since<br>adaptation is done via direct subclassing | Harder to override 's behavior; requires<br>using a subclass object rather than itself | | Only one object, with no extra<br>pointer indirection to access | Requires an extra pointer to indirectly access<brand adapt its behavior | Note: The Delegate pattern in Objective-C is essentially an Object Adapter. When to Use - When an existing class's interface does not match your requirements. - When you want a reusable class that can work with other classes that may have incompatible interfaces. - When you need to adapt several different subclasses of a class, but subclassing a class adapter for each one is impractical. In that case, use an object adapter (i.e., a delegate) to adapt the parent class's interface. Implementing the Adapter Pattern with Objective-C Protocols Class Adapter Object Adapter If we treat the MicroUSB interface adapter as merely a component of the charger, we get an object adapter. More Complex Use Cases in Cocoa As mentioned earlier, delegation is effectively an adapter relationship — specifically an object adapter. Take as an example: the goal is to transform the interface into the interface the client needs. What is the "client" here? It is the itself. What is the (the target interface)? It is and . The concrete class that implements these protocols () acts as the adapter. And what is the class that is incompatible with the framework and needs to be adapted? That would be the other classes in the application (). The reason we say the delegate mechanism is primarily an adapter pattern is that delegation can also realize the intent of other design patterns, such as the Decorator pattern. In practice, the delegate pattern is sometimes mixed together with other design patterns. Summary The Adapter pattern offers many benefits, such as decoupling the client from the adaptee and making client calls cleaner (only needing to call the defined interface methods). That said, it also has drawbacks: writing the adapter to fit the target interface can involve a relatively complex implementation, and it adds extra classes that make the architecture more complicated. Use it when it makes sense for your situation — do not force design patterns where they do not fit. References iOS Design Patterns Code All the code in this article can be found on my GitHub .