Welcome
to a series of posts dedicated to learning about design patterns.
Whilst a lot of the ideas are code-agnostic, we’re aiming to show you
how to implement them in Swift (Swift 3.0 as of the time of writing).
Each post is independent of each other and all code for the projects
will be available here on Git.

Okay,
so for todays example, picture your an iPhone, specifically the
Springboard on the iPhone. You have a grid of apps that a user can tap
at any point and execute. You also have a home button which closes your
apps (okay, it doesn't, it pushes them to the background, but stay with
us). Each app runs its own specific list of commands when it runs and
when it closes.
At the moment, when you — the iPhone — look at the Weather and Clock app, you see these functions exposed:

How do you start an app? Well I guess you would call getWeatherData() first on the WeatherApp, and then maybe showWeatherAnimation(). On the ClockApp, you would just have to call showClock(). A
bit confusing for the poor iPhone. Two completely different objects,
with no real way of knowing what to do without having prior knowledge of
how the objects work.
What
the iPhone needs to be able to do, is to encapsulate those commands
into another function so that it knows how to launch the app, without
having to have into intricate knowledge on how the app works. This is
solvable with the Command pattern. (This example was
really a stretch. The iPhone will use a much more complicated system is
real life, but it provides a nice visual idea that we can all picture in
our heads to demonstrate how the pattern works!)
What
the Command pattern allows us to do is to turn our Commands into
objects that will execute the correct list of functions depending on the
object, without having to modify the object itself (it would be a pain
if we had to ask the developers of these two applications to change
their codebase). For instance, we would create a class called WeatherAppOpen that would conform to a Command protocol, and would execute getWeatherData() and showWeatherAnimation() when a generic execute() function is called.
This is what the Command pattern for the iPhone’s Springboard looks like in UML form:

The
Springboard never communicates directly with the WeatherApp because the
necessary commands are abstracted to a common generic method, meaning
the Springboard only needs to be aware of one method.
How that looks in code
To start, create a new project in Xcode. We won’t be touching anything in UIKit so create a macOS Terminal project.
We’ll
create the Command protocol first that all of our command classes will
conform to. Its relatively simple, and just contains the execute() function that the Springboard will talk to.
Next,
we’ll create our WeatherApp and ClockApp classes. These classes will
just contain some boilerplate methods that print out to the console so
we could see what our theoretical Springboard would be doing. They will
look like this:
We
now need to access those methods via the Command protocol. To do this,
we create the object as the type of Command we wish to complete I.E open
or close the app. Starting with opening the Weather app, we’ll create WeatherAppOpenCommand.
We
invoke the class by passing through an instance of the Weather App (if
this was real life, that would probably be a Singleton in the case of
the iPhone — post coming soon!). When execute() is
called, we then launch the app, using the specific commands to the
Weather App. We do the same with closing the Weather App, which looks
like this:
Starting
to get the picture? We can then build the Clock App commands in exactly
the same way, but call the methods specific to the Clock App:
We can now look at building our pretend (and very simplistic) Springboard.
The
Springboard needs to be able to hold an array of open and close
commands (our apps). It then needs to be able to execute a command at
specific index if an app is available. It will look like so:
The setCommand function allows us to effetely place an app at an index on the Springboard, and the open/closeApp functions allow us to execute the correct command at the index provided.
So now we’ll build the client (or the iPhone in this case).
We
create an instance of the Springboard, an instance of the Weather App,
and an instance of the Clock App. We set the commands using the
Open/Close objects relative to each app, and pass through the instance
of the app to the relevant commands.
Run the program, and you’ll get an output that looks like this:
Getting weather data
Showing correct weather animation
Deleting weather data
Closing weather appShowing clock
Removing clock
Hurray
you built an iPhone*! You’re running the apps, in an expandable,
encapsulated way, that the Springboard knows nothing about!
Comments
Post a Comment