By the end of this lesson, you should be able to...
- Describe:
- the Chain-of-Responsibility and Command patterns
- the software problem each is intended to solve
- potential use cases for each (when to use them)
- Assess:
- the suitability of a given design pattern to solve a given problem
- the trade offs (pros/cons) inherent in each
- Implement basic examples of both patterns explored in this class
- A Quiz on last class content & after class section
In software engineering, Behavioral design patterns are design patterns that identify common communication patterns between objects.
By doing so, these patterns increase flexibility in carrying out such communications.
Though there are many more to explore, we will focus on these two key Behavioral patterns in this lesson:
- Chain-of-Responsibility (CoR)
- Command
The Chain-of-Responsibility pattern is a behavioral design pattern that allows an event to be processed by one of many handlers.
It consists of a source of command objects and a series of processing objects.
Each processing object contains logic that defines the types of command objects that it can handle; the rest are passed to the next processing object in the chain.
Source: wikipedia.org
There are several objects that can handle a request but only one of them should be used.
You define a chain of receiver objects having the responsibility, depending on run-time conditions, to either handle a request or forward it to the next receiver on the chain (if any).
This enables sending a request to a chain of receivers without having to know which one handles the request.
The request gets passed along the chain until a receiver handles the request. The sender of a request is no longer coupled to a particular receiver.
The Cocoa and Cocoa Touch frameworks actively use the chain-of-responsibility pattern for handling events.
Objects that participate in the chain are called responder objects, inheriting from the UIResponder
(iOS) class.
All view objects (UIView), view controller objects (UIViewController), window objects (UIWindow), and the application object (UIApplication) are responder objects
Typically, when a view receives an event it can’t handle, it dispatches it to its superview until it reaches the view controller or window object.
If the window can’t handle the event, the event is dispatched to the application object, which is the last object in the chain.
Source: Apple, Inc.
25 min Follow this activity in groups of 2 or 3.
10 min Walkthrough solution
Command is a design pattern in which an object is used to encapsulate all information needed to perform an action or trigger an event at a later time.
This information includes the method name, the object that owns the method and values for the method parameters
It turns a request/action into a stand-alone object that contains all information about the request.
This transformation lets you parameterize methods with different requests, delay or queue a request’s execution, and support undoable operations.
It involves three component types:
-
The invoker stores and executes commands.
-
The command encapsulates the action as an object.
-
The receiver is the object acted upon by the command.
It should be possible to configure an object (that invokes a request) with a request.
Implementing (hard-wiring) a request directly into a class is inflexible because it couples the class to a particular request at compile-time, which makes it impossible to specify a request at run-time.
- Single Responsibility Principle.
- Open/Closed Principle. (Introduce new commands into the app without breaking existing code)
- You can implement undo/redo.
- You can implement deferred execution of operations.
- You can assemble a set of simple commands into a complex one.
- When you want to parametrize objects with operations.
- When you want to queue operations, schedule their execution, or execute them remotely.
- When you want to implement reversible operations.
The most well-known use of this pattern:
In some strategy games, the ability to rollback moves the user did not like is an essential user experience feature. The command pattern simplifies the implementation of Undo
and Redo
user actions.
Follow this activity
- The other Behavioral Patterns in the links below
- Research the following concepts:
- The Composite Pattern
UndoManager
(in Foundation framework)UIEvent
ObjectsTouch
Objects- All Touch Events (e.g.,
touchesEnded(_:_:)
) - the
hitTest(_:With:)
function
Stretch Challenge Using Apple's Media Player framework, implement a simple (i.e., basic UI only) iPhone app that will play, pause, and restart (skip to beginning) the following sample file (or any video/audio file of your choice):
Archived activity CoR (But you can try it out)
- Behavioral Patterns - an article
- Behavioral pattern - wikipedia
- Chain-of-Responsibility - wikipedia
- Command pattern - wikipedia
- Intermediate Design Patterns in Swift - Ray Wenderlich
- Using Responders and the Responder Chain to Handle Events - from Apple
- Design Patterns in Swift: Chain of Responsibility Pattern - an article
- Refactoring guru - Chain
- Refactoring guru - Command
- Gang Of Four Cheat Sheet
For The More Curious
- Using the Debug View Hierarchy tool on this simple example reveals little of the powerful utility this tool can have in analyzing your code.
- TODO: To understand more of how this tool can be used, experiment with it on some of your actual projects that have more complex UI architectures.
- Apple has long provided ways to analyze view hierarchies. In addition to the Debug View Hierarchy tool, there have been several command-line debugging phrases which can be used to analyze the view hierarchy of your app during runtime.
One example: You can return information about the state of your current view hierarchy by setting a breakpoint and executing the following command in your debug pane:
expr -l objc++ -O -- [UIViewController _printHierarchy]
The output from this command can provide information useful in debugging your views: