Skip to main content

Design Patterns in Swift: Command Pattern

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.


iPhone Springboard

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:


Well, thats confusing

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.
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:
Hurray you built an iPhone*! You’re running the apps, in an expandable, encapsulated way, that the Springboard knows nothing about!

Comments

Popular posts from this blog

Swift GCD part 1: Thread safe singletons

Preview Singletons are entities, referenced to the same instance of a class from everywhere in your code. It doesn't matter if you like them or not, you will definitely meet them, so it's better to understand how they work. Constructing and handling a set of data doesn't seem to be a big challenge at first glance. The problems appear when you try to optimise the user experience with background work and your app starts acting weird. ??‍♂️ After decades of watching your display mostly with a blank face, you finally realize that your data isn't handled consistently by the manager because you're accessing it (running tasks on it) from multiple threads at the same time. So you really do have to deal with making your singletons thread safe. This article series is dedicated to thread handling using Swift. In the first part below you will get a comprehensive insight into som...

Kiến thức cơ bản về RxSwift

Bài viết với mong muốn cung cấp thông tin cơ bản về kiến trúc, các thuật ngữ được sử dụng phổ biến về RxSwift, giúp những lập trình viên lần đầu làm quen RxSwift sẽ trở nên dễ dàng hơn. Trong bài viết có sử dụng một số từ khóa tiếng Anh, mình xin phép sẽ giữ nguyên bản không sử dụng tiếng Việt vì có lẽ sẽ dễ hiểu hơn cho người đọc. Observable Sequences Mọi hoạt động trong RxSwift từ việc đăng ký và xử lý sự kiện đều thông qua một Observable Sequences Trong RxSwift , các kiểu dữ liệu như Arrays , Strings hoặc Dictionary sẽ được convert sang Observable Sequences . Ta có thể tạo ra "Observable Sequences" của bất kỳ kiểu đối tượng nào tuân theo Sequence Protocol của Swift Standard Library . let helloSequence = Observable.just( "Hello Rx" ) let fibonacciSequence = Observable. from ([ 0 , 1 , 1 , 2 , 3 , 5 , 8 ]) let dictSequence = Observable. from ([ 1 : "Hello" , 2 : "World" ]) Đăng ký nhận event từ ""Observable Se...

Thread safe singleton’s in Swift

What are singletons? — Singleton is design patterns which says that there should be only one instance of the class for the lifetime of the application. One the best example of Singleton is AppDelegate . How to write a singleton class ? class DefaultDict{ private var dict:[String:Any] = [:] public static let sharedManager = DefaultDict() private init(){ } public func set(value:Any,key:String){ dict[key] = value } public func object(key:String) -> Any?{ dict[key] } public func reset(){ dict.removeAll() } }   Testing singleton class under concurrent circumstances. We are going to write an example where we will set values in dict from various threads and even try to access some with different threads. When we do this we will encounter a crash. If you look closely it will be because of race condition and the crash will be on line set(value:Any,key:String) . class ViewController: UIViewController { ...