Download Design Patterns: Singleton, Command, Adaptor, and Facade Patterns - Prof. Kenneth M. Ander and more Study notes Computer Science in PDF only on Docsity!
Singleton, Command, & Adaptor
Kenneth M. Anderson University of Colorado, Boulder CSCI 4448/6448 — Lecture 21 — 11/04/ VOTE! © University of Colorado, 2008
Lecture Goals
- Cover Material from Chapters 5 — 7 of the Design Patterns Textbook
- Singleton Pattern
- Command Pattern
- Adaptor Pattern
- Facade Pattern 2
Singleton Pattern: Structure
static getInstance() : Singleton private Singleton() static my_instance : Singleton
Singleton Singleton involves only a single class (not
typically called Singleton). That class is a
full-fledged class with other attributes
and methods (not shown)
The class has a static variable that points
at a single instance of the class.
The class has a private constructor (to
prevent other code from instantiating the
class) and a static method that provides
access to the single instance
4
World’s Smallest Java-based Singleton Class
1 public class Singleton { 2 3 private static Singleton uniqueInstance; 4 5 private Singleton() {} 6 7 public static Singleton getInstance() { 8 if (uniqueInstance == null) { 9 uniqueInstance = new Singleton(); 10 } 11 return uniqueInstance; 12 } 13 } 14
Meets Requirements: static var, static method, private constructor
Example source has this class in ken/smallest augmented with test code 5
World’s Smallest Ruby-based Singleton Class
1 require 'singleton'
3 class Example
4 include Singleton
5 end
7 a = Example.instance
8 b = Example.instance
10 puts "a = #{a}"
11 puts "b = #{b}"
13 c = Example.new
Yet a different approach, using a
mechanism in Ruby called a
“mixin”
The “include Singleton” statement
causes the Example class to be
modified such that its new()
method becomes private and an
instance() method is added to
retrieve an instance. As a bonus, it
will also handle hiding allocate(),
overriding the clone() and dup()
methods, and is thread safe!
Only 5 lines of code!
7
Thread Safe?
- The Java and Python code just shown is not thread safe
- This means that it is possible for two threads to attempt to create the singleton for the first time simultaneously
- If both threads check to see if the static variable is empty at the same time, they will both proceed to creating an instance and you will end up with two instances of the singleton object (not good!) - Example Next Slide 8
Output for Non Thread-Safe Singleton Code
- s9 = Singleton@45d
- s8 = Singleton@45d
- s3 = Singleton@45d
- s6 = Singleton@45d
- s1 = Singleton@45d
- s0 = Singleton@ab50cd
- s5 = Singleton@45d
- s4 = Singleton@45d
- s7 = Singleton@45d
- s2 = Singleton@45d
Whoops!
Thread 0 created an instance of the Singleton class at memory location
ab50cd at the same time that another thread (we don’t know which one)
created an additional instance of Singleton at memory location 45d068!
10
How to Fix?
1 public class Singleton { 2 3 private static Singleton uniqueInstance; 4 5 private Singleton() {} 6 7 public static synchronized Singleton getInstance() { 8 if (uniqueInstance == null) { 9 uniqueInstance = new Singleton(); 10 } 11 return uniqueInstance; 12 } 13 14 } 15
In Java, the easiest fix is to add the synchronized keyword to the
getInstance() method. The book talks about other methods that address
performance-related issues. My advice: use this approach first! 11
Command Pattern: Structure
action() Receiver setCommand() Invoker execute() undo() Command execute() undo() ConcreteCommand public void execute() { receiver.action() }
I’m leaving one piece out of this diagram: the client.
In order for this pattern to work, someone needs to create a command
object and set its receiver. And, someone needs to give command objects
to an invoker to invoke at a later time.
Those “someones” may be the same object, they may be different objects
Waitress
Cook Order
13
Example: Remote Control
- The example in the textbook involves a remote control for various household devices. - Each device has a different interface (plays role of Receiver) - Remote control has uniform interface (plays role of Client): “on” and “off” - Command objects are created to “load” into the various slots of the remote control - Each command has an execute() method that allows it to emit a sequence of commands to its associated receiver - Light: turn light on - Stereo: turn Stereo on, select “CD”, play()
- In this way, the details of each receiver are hidden from the client. The client simply says “on()” which translates to “execute()” which translates to the sequence of commands on the receiver: nice loosely-coupled system 14
Macro Commands
- Another nice aspect of the Command pattern is that it is easy to create Macro commands. - You simply create a command that contains an array of commands that need to be executed in a particular order - execute() on the macro command, loops through the array of commands invoking their execute() methods - undo() can be performed by looping through the array of commands backwards invoking their undo() methods
- From the standpoint of the client, a Macro command is simply a “decorator” that shares the same interface as normal Command objects - This is an example of one pattern building on another 16
Demonstration
- The example code for this lecture demonstrates several aspects of the Command pattern - Simple commands - Simple Undo - Macro Commands 17
Additional Uses: Logging
- This variation involves adding store() and load() methods to command objects that allow them to be written and read to and from a persistent store - The idea is to use Command objects to support system recovery functionality
- Imagine a system that periodically saves a “checkpoint” of its state to disk
- Between checkpoints, it executes commands and saves them to disk
- Imagine the system crashes
- On reboot, the system loads its most recent “checkpoint” and then looks to see if there are saved commands - If so, it executes those commands in order, taking the system back to the state it was in just before the crash 19
Adapters in the Real World
- Our next pattern provides techniques for converting an interface that is not compatible with an existing system into a different interface that is - Real World Example: AC Power Adapters - Electronic products made for the USA cannot be used directly with electrical outlets found in most other parts of the world - US 3-prong (grounded) plugs are not compatible with European wall outlets - To use, you need either - an AC power adapter, if the US product has a “universal” power supply, or - an AC power convertor/adapter, if it doesn’t
- By example, OO adapters may simply provide adaptation services from one interface to another, or may require more smarts to convert information from one interface before passing it to the second interface 20