Design Patterns - A Cheatsheet
This is a short note curated by me for fast reference of design patterns. All content is derived from the book "Design Patterns For Dummies" by Steve Holzner, PhD
The Mediator Pattern
You can use a mediator here to encapsulate all the navigation code out of the separate pages and place it into a mediator object instead. From then on, each page just has to report any change of state to the mediator, and the mediator knows what page to send the user to.
Adapter Pattern
Convert the interface of a class into another interface the client expects. Adapter lets classes work together that couldn’t otherwise because of incompatible interfaces
Proxy Pattern
A proxy is a stand-in for another object that makes the local code think it’s dealing with a local object. Behind the scenes, the proxy connects to the remote object, all the while making the local code believe it’s working with a local object
Observer Pattern
The Observer design pattern is about passing notifications around to update a set of objects when some important event has occurred. You can add new observer objects at runtime and remove them as needed. When an event occurs, all registered observers are notified.
The big four OOP building blocks
- Abstraction: Abstraction is all about breaking your approach to a problem into natural segments. This is where you come up with the objects that divide the problem into manageable parts.
- Encapsulating: hide the complexities inside objects and then create a simple interface to let that object interact with the rest of your code.
- polymorphism: perform various actions on the shapes you’re working with — and then decide on the actual shape(s) you want to use at runtime. Polymorphic (which means many form) code works with any such shape without being rewritten.
- Inheritance: the process by which one class can inherit methods and properties from another.
With inheritance, base classes and derived classes have an “is-a” relationship.
Composition Example:
public interface GoAlgorithm {
public void go();
}
public class GoByFlying implements GoAlgorithm {
public void go() {
System.out.println(“Now I’m flying.”);
}}
public abstract class Vehicle {
private GoAlgorithm goAlgorithm;
public Vehicle() {
}
public void setGoAlgorithm (GoAlgorithm algorithm) {
goAlgorithm = algorithm; }
public void go() { goAlgorithm.go();
}
}
public class Helicopter extends Vehicle {
public Helicopter() {
setGoAlgorithm(new GoByFlyingAlgorithm()); }
}
Advantage: Can change behavior at runtime
Strategy Pattern
The Strategy design pattern says that you should extract the volatile parts of your code and encapsulate them as objects; you can use those objects as you need them
At runtime, you just use polymorphism to choose the object(s) you want to work with
“Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.”
Decorator Pattern
“Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.”
Example
public class Computer {
public Computer() {
}
public String description() {
return “computer”; }
}
public abstract class ComponentDecorator extends Computer {
public abstract String description();
}
public class Disk extends ComponentDecorator {
Computer computer;
public Disk(Computer c) {
computer = c; }
public String description() {
return computer.description() + “ and a disk”; }}
public class Test {
public static void main(String args[]) {
Computer computer = new Computer();
computer = new Disk(computer); computer = new Monitor(computer); computer = new CD(computer); computer = new CD(computer);
System.out.println(“You’re getting a “ + computer.description() + “.”);
}
}
Factory Pattern
Define an interface for creating an object, but let subclasses decide which class to instantiate. The factory method lets a class defer instantiation to subclasses
Example
public abstract class ConnectionFactory {
public ConnectionFactory() {
}
protected abstract Connection createConnection(String type);
}
public class SecureFactory extends ConnectionFactory {
public Connection createConnection(String type) {
if (type.equals(“Oracle”)){
return new SecureOracleConnection();
}
else if (type.equals(“SQL Server”)){
return new SecureSqlServerConnection(); }
else {
return new SecureMySqlConnection();
}
}
}
Observer Pattern
Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically
There’s a subject and observers. Observers can be registered or unregistered on the subject. The subject sends notifications to all registered observers.
Interfaces
public interface Subject {
public void registerObserver(Observer o); public void removeObserver(Observer o); public void notifyObservers();
}
public interface Observer {
public void update(String operation, String record);
}
Chain of Responsibility Pattern
Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it.
Example
interface HelpInterface {
public void getHelp(int helpConstant);
}
public class FrontEnd implements HelpInterface {
final int FRONT_END_HELP = 1;
HelpInterface successor;
public FrontEnd(HelpInterface s) {
successor = s; }
public void getHelp(int helpConstant) {
if(helpConstant != FRONT_END_HELP){ successor.getHelp(helpConstant);
} else {
System.out.println(“This is the front end. Don’t you like it?”);
} }}
public class IntermediateLayer implements HelpInterface {
final int INTERMEDIATE_LAYER_HELP = 2;
HelpInterface successor;
public IntermediateLayer(HelpInterface s) {
successor = s; }
public void getHelp(int helpConstant) {
if(helpConstant != INTERMEDIATE_LAYER_HELP){ successor.getHelp(helpConstant);
} else {
System.out.println(“This is the intermediate layer. Nice, eh?”);
} }
}
public class Application implements HelpInterface {
public Application() {
}
public void getHelp(int helpConstant) {
System.out.println(“This is the MegaGigaCo application.”); }
}
public class TestHelp {
public static void main(String args[]) {
final int FRONT_END_HELP = 1;
final int INTERMEDIATE_LAYER_HELP = 2; final int GENERAL_HELP = 3;
Application app = new Application();
IntermediateLayer intermediateLayer = new IntermediateLayer(app);
FrontEnd frontEnd = new FrontEnd(intermediateLayer);
frontEnd.getHelp(GENERAL_HELP);
}
}
Singleton Pattern
Ensure a class only has one instance, and provide a global point of access to it.
You use the Singleton design pattern when you want to either restrict resource use (instead of creating numbers of large objects without limit) or when you have a sensitive object whose data shouldn’t be accessed by multiple instances (such as a registry).
Private constructor and public static access point to an instance
Flyweight Pattern
Flyweight pattern must, “Use sharing to support large numbers of fine-grained objects efficiently.”
A flyweight is a shared object that can be used in multiple contexts simultaneously. The fly-weight acts as an independent object in each context it’s indistinguishable from an instance of the object that’s not shared.
Facade Pattern
It’s fundamentally a design issue — if an object or class interface is too hard to work with, the Facade pattern gives you a front end to that interface to make it easier.
“Provide a unified interface to a set of interfaces in a system. Facade defines a higher-level interface that makes the subsystem easier to use.”
Example
public class SimpleProductFacade {
DifficultProduct difficultProduct;
public SimpleProductFacade() {
difficultProduct = new DifficultProduct(); }
public void setName(String n) {
char chars[] = n.toCharArray();
if(chars.length > 0){ difficultProduct.setFirstNameCharacter(chars[0]);
}
.
.
.
if(chars.length > 6){
difficultProduct.setSeventhNameCharacter(chars[6]); }
}
public String getName() {
return difficultProduct.getName(); }
}
Template Method pattern
Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. The Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm’s structure.
“executes a multi-step algorithm that’s customizable by subclasses”
Example
public abstract class RobotTemplate {
public final void go() {
start(); getParts(); assemble(); test(); stop();
}
. . .
}
public class AutomotiveRobot extends RobotTemplate {
public void getParts() {
System.out.println(“Getting a carburetor....”); }
public void assemble() {
System.out.println(“Installing the carburetor....”); }
public void test() {
System.out.println(“Revving the engine....”); }
}
Builder Pattern
Separate the construction of a complex object from its representation so that the same construction processes can create different representations.
The main difference between the Template Method and the Builder design patterns is in who creates the sequence of steps in the algorithm.
Iterator Pattern
Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation.
Composite Pattern
The Composite pattern is all about creating tree-like structures where the leaves in a structure can be treated in the same way as the branches (which are substructures that can contain multiple leaves, as well as other branches).
“Compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly.”
use an abstract class as the basis for both the leaves and branches in the tree
State Pattern
Allow an object to alter its behavior when its internal state changes. The object will appear to change its class.
Comments ()