iOS

Design Patterns in Swift #3: Facade and Adapter


This tutorial is the third installment in our series on design patterns. I started
this series with a tutorial examining two examples of patterns in the “creational” category: factory method and singleton. I then discussed two examples of patterns in the “behavioral” category: observer and memento.

In this tutorial, I’ll explain two examples of patterns in the “structural” category: facade and adapter. I urge you to review my first two posts mentioned above so you can familiarize yourself with the concept of software design patterns. Beyond a brief reminder today of what constitutes a design pattern, I’m not going to regurgitate all the definitions again. All the information you need to get up to speed is in my first two tutorials, here and here.

Let’s briefly review some general definitions of design patterns here and in the next few sections. There are 23 classic software development design patterns probably first identified, collected, and explained all in one place by the “Gang of Four” (“GoF”), Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides in their seminal book, “Design Patterns: Elements of Reusable Object-Oriented Software.”. Remember that today we’ll focus on two of these patterns, facade and adapter, which fall into what the GoF calls the “structural” category.

Protocol-oriented code with value semantics

You’ll still find that many tutorials about design patterns contain sample code based on object-oriented programming (OOP) principles, reference semantics, and reference types (classes). I am endeavoring to create a series of tutorials on design patterns that are mostly based in protocol-oriented programming principles (POP), value semantics, and value types (structs). If you’ve reviewed the first two articles in this series, I hope you followed my advice and familiarized yourselves with POP versus OOP and reference semantics versus value semantics. If not, I strongly encourage you to get up to speed on these topics. This tutorial is solely based in POP and value semantics.

Design Patterns

Design patterns are an extremely important tool with which developers can manage complexity. It’s best to conceptualize them as generally templated techniques, each tailored to solving a corresponding, recurring, and readily identifiable problem. Look at them as a list of best practices you would use for coding scenarios that you see over and over again. To make this definition tangible, think of how many times you’ve either used code or written code that conforms to the observer design pattern.

In observer, the subject instance, usually a single critical resource, broadcasts notifications about a change in its state to many observer instances that depend on that resource. Interested observers must tell the subject instance that they’re interested in receiving notifications, in other words, they must subscribe to get notifications. Encoding iOS push notifications, where users must opt into receiving messages, is a great example of observer.

Design pattern categories

The GoF organized their 23 design patterns into three categories, “creational,” “behavioral,” and “structural.” This tutorial discusses two patterns in the structural category. Consider the word “structure,”

“something arranged in a definite pattern of organization” and “the aggregate of elements of an entity in their relationships to each other.”

- https://www.merriam-webster.com/dictionary/structure

Structural design patterns are meant to help you to clearly define the purpose of a segment of code and clearly specify how other code interacts with that segment. Most patterns in this category enable you to simplify the use of your code. We can usually simplify use of code by creating an easily readable interface to that code. Since pieces/segments of code don’t exist in a vacuum, providing a good interface to a code segment should obviously and cleanly define the possible relationships that can be built between that segment and other segments.

The facade design pattern

The word “facade” is defined as “any face of a building given special architectural treatment” and “a false, superficial, or artificial appearance or effect.”

- https://www.merriam-webster.com/dictionary/facade

In most cases, we use the facade pattern to create one simple interface to a group of other, possibly many, and usually complex, interfaces. You have probably already created what are commonly called “wrappers” where you built a simple interface to a complex codebase with the purpose of simplifying the use of that codebase.

Use case for facade design pattern app

My facade example playground, available on GitHub, showcases how this pattern can create one simple interface to the sandboxed file system available to each iOS app. The iOS file system is a huge OS subsystem, allowing you to create, read, delete, move, rename, and copy files and directories; allowing you to get (and sometimes set) meta data about files and directories, e.g., list the files in a directory; allowing you to check the status of files/directories, e.g., determine if a file is writable; and, providing you with the names of predefined directories in which Apple prefers that you work. Note that you can do much more than what I just listed.

Since the iOS file system is such a grand topic with many different features and functions, it is an ideal candidate for using the facade design pattern to simplify its usage. A facade interface allows you to leave out functionality you don’t need and that may clutter your code. Conversely, a facade interface allows you to specify only the functionality you need for a particular app, or in my case, to limit functionality to what I have found to be only the features I have used over time, and thus make my facade reusable, extensible, and maintainable for many of my apps.

I used protocol-oriented programming and value semantics for dividing and conquering major features of the iOS file system into reusable and extensible units: protocols and protocol extensions.

I then composed four protocols into one struct that represents a sandboxed iOS directory available to all iOS apps (see also here). Since you’re likely to run across the topics of POP and value semantics more and more, note that the terms composed and composition are synonymous herein.

Note that I left Swift error handling and more generic error checking out of the code shown below solely for didactic purposes, i.e., so you can more easily concentrate only on understanding use of the facade pattern.

Sample code for the facade design pattern

Let’s walk through my code. Make sure you follow along with my code in the playground hosted on GitHub. Here’s a list of predefined directories in which Apple prefers you do much of your iOS app’s work:

By constraining my file manipulation code to these known directories, I control complexity, simplify, and stay within the bounds of the Human Interface Guidelines.

Before looking at my core code for file manipulation, let’s first look at my facade design pattern-based interface as that’s the topic of this tutorial. I created the iOSAppFileSystemDirectory struct as a simple and readable interface to common file system features available for each of the directories specified in my AppDirectories enum. Yes, I could get involved with things like the creation of symbolic links or the use of fine grained manipulation of individual files using the FileHandle class, but I almost never use these features, and most importantly, I’m deliberately keeping things simple.

I’ve created a facade composed of four protocols (I know you see three immediately below, but one of the protocols inherits from another):

Here’s some code that tests my iOSAppFileSystemDirectory struct:

Here’s the output to console from executing the previous code snippet in my playground:

Let’s briefly discuss the protocols that were used to compose iOSAppFileSystemDirectory. Here we have the AppDirectoryNames protocol and protocol extension which compartmentalize the retrieval of full paths of type URL to the Apple-predefined directories as specified in my AppDirectories enum:

AppFileStatusChecking is my protocol and protocol extension that encapsulate getting state data about files stored in directories as specified in my AppDirectories enum. By “state,” I mean determining if a file exists, if it’s writable, etc.

AppFileSystemMetaData is my protocol and protocol extension that compartmentalize listing directory contents and getting extended file attributes, both from directories as specified in my AppDirectories enum:

Finally, the AppFileManipulation protocol and protocol extension encapsulate the reading, writing, deleting, renaming, moving, copying, and changing the file extension of files located in directories as specified in my AppDirectories enum:

The adapter design pattern

The word “adapt” is defined as “to make fit (as for a new use) often by modification.”

- https://www.merriam-webster.com/dictionary/adapts

The word “adapter” is defined as “an attachment for adapting apparatus for uses not originally intended.”

- https://www.merriam-webster.com/dictionary/adapter

The adapter pattern is used so that an existing codebase (call it “A”) can work, without modifying the original “A” code, with other code (call it “B”) that may not be completely compatible with the existing, original codebase “A.” We can create some kind of adapter that allows “A” and “B” to work together despite their differences. Remember that the existing, original codebase “A” cannot be modified (either because it would break the code or because we don’t have the source).

Use case for adapter design pattern app

My adapter example playground, available on GitHub, showcases how we’ll use the iOS file system as a substrate on which to discuss and design an example of the adapter pattern. Let’s say we’ve got my iOS file system code from the preceding sections up above where all paths to directories and files are expressed as URL instances. Consider a scenario in which we’ve been given a huge chunk of code that also manipulates the iOS file system, but where all paths to directories and files are expressed as String path instances, and the URL-based code must be made to work with the String path-based code.

Sample code for the adapter design pattern

Let’s walk through my code. Make sure you follow along with my code in the playground hosted on GitHub. In order to concentrate solely on the adapter pattern, we’ll use slimmed-down versions of my AppDirectories enum and AppDirectoryNames protocol and protocol extension:

One technique we could use is to create a “dedicated” adapter, one which gives us string-based paths to directories as specified in AppDirectories and also gives us string-based paths to files stored in directories as specified in AppDirectories:

Here’s some code that tests the iOSFile “dedicated” adapter — and note my one inline comment:

Here are my playground’s line-by-line annotations which appear to the right of each line of code, on the same line, representing runtime code values, corresponding to the previous code snippet — the annotations below correspond one-to-one to the lines of code above:

The technique I prefer is to design an adapter protocol that my string path-based code could adopt so that it could use String paths instead of URL paths.

Here’s some code that tests my AppDirectoryAndFileStringPathNames struct, which adopts the AppDirectoryAndFileStringPathNamesAdpater adapter protocol (which is a descendent of the AppDirectoryNames protocol) — and note my two inline comments:

Here are my playground’s line-by-line annotations which appear to the right of each line of code, on the same line, representing runtime code values, corresponding to the previous code snippet — the annotations below correspond one-to-one to the lines of code above:

Conclusion

Not only do design patterns encourage code reuse, but can help you make your code consistent, readable, loosely coupled, and thus maintainable and extensible. When you identify recurring and generalized features in your apps, I encourage you to take your design pattern-based code and put it into frameworks so you write it once and use it many more times.

Thanks for joining me again here on AppCoda. Enjoy your work, keep on learning, and I’ll see you soon!

iOS
Introduction to Core ML: Building a Simple Image Recognition App
iOS
Core Image Introduction: Applying Image Filters to Photos
iOS
Core Data Part 2: Update, Delete Managed Objects and View Raw SQL Statement
Shares