Design Patterns
The majority of this article comes from Head First Design Patterns and Oxford Imperative Programming 3 lectures.
Identity the aspects of the application that vary and separate them from what stays the same.
- The Strategy Pattern defines a family of algorithms, encapsulates each one, and makes them interchangeable. Strategy lets the algorithm vary independently from clients that use it.
- The Observer Pattern defines a one-to-many dependency between objects so that when one object changes state, all of its dependents are notified and updated automatically.
Picture it as publishers (formally, subject)+ subscribers (formally, observer)!
Strive for loosely coupled designs between objects that interact!
- Decorator Pattern attaches additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.
Think of decorator objects as “wrappers.”
Things to know:
- Decorators have the same supertype as the objects they decorate. → We can pass around a decorated object in place of the original (wrapped) object. N.B. Decorators are typically transparent to the client of the component — unless the client is relying on the component’s concrete type.
- You can use one / more decorators to wrap an object.
- The decorator adds its own behavior either before and/or after delegating to the object it decorates to do the rest of the job.
Classes should be open for extension, but closed for modification!
- Command Pattern encapsulates a request as an object, thereby letting you parameterize other objects with different requests, queue or log requests, and support undoable operations.
When to use it? When you need to decouple an object making requests from the object that know how to perform the requests!
A command object composes a receiver and a method for execution.
Requests logging: store the commands (rather than the large data structures) each time a change is made, so that we can recover after a crash.
- Factory Method Pattern defines an interface for creating an object, but lets subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.
The creator class is written without knowledge of the actual products that will be created, which is decided purely by the choice of the subclass that is used.
Design upon abstractions. Do not depend upon concrete classes. — Dependency Inversion Principle
- Abstract Factory Pattern provides an interface for creating families of related or dependent objects without specifying their concrete classes.
DIFFERENCE between factory method & abstract factory:
- Factory method: an abstract factory subclassed by concrete factories; subclasses of this factory override a factory method; you use a subclass to do the creation for you.
- Abstract factory: an abstract type for creating a family of products; subclasses of this type defines how each product is created; to use the factory, you instantiate one and pass it into some code through composition.
- Adapter Pattern converts the interface of a class into another interface the clients expect. Adapter lets classes work together that couldn’t otherwise because of incompatible interfaces.
The adapter can achieve the conversion either by composing an adaptee and implementing the Target interface OR through multiple inheritances (both the Target and the Adaptee).
- Facade Pattern provides a unified interface to a set of interfaces in a subsystem. Facade defines a higher-level interface that makes the subsystem easier to use.
It also decouples a client from a subsystem of components.
Principle of Least Knowledge — talk only to your immediate friends.
Comparison of the INTENT of 3 patterns:
Adapter: converts one interface to another
Decorator: doesn’t alter the interface, but adds responsibility
Facade: makes an interface simpler