Software design patterns
Bridge
Decouple abstraction from its implementation so that 2 can very independently
- avoid permanent binding (so you can switch easily)
- both elements can be extended
- avoid recompiling one when there are changes on the other
- 4 elements
- abstraction (BO) - interface
- redefined abstraction (customers BO) class
- implementor (Data object) - interface
- concrete implementor (customer data object) -class
- example: client
- Abstraction -> RefinedAstraction
(Shape: Circle, Rectangle)
- Implementor -> ConcreteImplementorA, ConcreteImplementorB
(Drawing: DrawingA, DrawingB)
- Abstraction -> RefinedAstraction
- representation
graph LR; A[Abstraction]; B[Refined abstraction]; C[Implementor]; D[Concrete implementor]; C-->A; B-.->A; D-.->C;
- consequences
- decoupling
- improved exetensibility
- hiding implementation details from clients
- Related pattern: adapter: unrelated classes working together
Builder
Splits construction and representation -> Factory vs BO
- 4 elements
- Director (builds something)
- Builder (abstract) -> does the consctruction the director requires
- ConcreteBuilder -> created externally, actually builds
- Product (built by the Builder under the Director direction)
- representation
graph LR; A[Director]; B[Builder: Concrete Builder]; C[Product]; A-->B; B-->C;
- consequences
- Products internal representation
- Control + isolation over construction process
Command: encapsulating invocation
Encapsulate method invocation - abstraction (e.g. single remote control for different devices: many on-off switches)
- 4 elements
- Client - creates command, chooses receiver
- Receiver - knows how to perform the action
- Concrete Command - binds action and receiver: execute() and undo()
- Invoker (holds commands) –> ICommand (interface for all commands)
- consequences
- Package computation (loggng, transactional systems)
- Decoupled job queues with “macro commands”
- Bad stuff: time consuming, bloated commands
- representation
graph LR; A[Client]; B[Receiver]; C[Concrete Command]; D[Invoker]; E[ICommand]; A-->B; A-->C; D-->E;
❗ Notes:
- There can be a NoCommand (empty slot in a controller)
- There can be an undo method (e.g. turn off lightbulb on controller)
Decorator
Structural, add behaviour to a particular object, as opposed to class objets (the others are unmodified)
(e.g. java.io.Reader/*component*/
: InputStreamReader/*concreteComponent*/
and BufferedReader /*decorator*/
)
- 3 elements
- Component
(hang())
- ConcreteComponent
(hang())
//inheritance from Component - Decorator
(hang())
//inheritance from Component, uses component
- Component
- representation
graph TD; A[Component]; B[Concrete Component]; C[Decorator]; B-.->A; C-.->A; C-->B;
- consequences
- original object ‘not polluted’
- flexible
- doesn’t require source from original object
- fewer classes than inheritance
Factory aka virtual constructor
Creational design pattern, as can’t anticipate which classes will be generated
- 4 elements
- Creator: abstract, provides full default implementation
- Concrete Creator
- Product
- Concrete Product
- representation
graph LR; A[Creator: Concrete creator]; B[Product: Concrete product]; A-->B
Singleton
Unique instance without using an static class, so the class can be easily mocked and tested
1 | public class Singleton{ |