-
Notifications
You must be signed in to change notification settings - Fork 0
design patterns
Generic solution (pattern) catalogue to solve recurring common situations in a certain context. It's important to mention that we try to separate the pattern from the actual implementation.
- GoF (gang of four) book
- "UML" diagrams: not as the current standard (at the time of writing the GoF book the UML standard did not exist yet)
- Usage: mostly obsolete
- Using design patterns could cause longer run-time; however typically only some specific part of a program is critical (for real-time processing); for all other parts design patterns can and should be used
- Questions useful for an evaluation:
- When do we get delays? (init, during time-critical code execution, background process, ...)
- How often do we need to pay the overhead? (1000 times per second, once (during init), edge-cases, ...)
- Which amount of (time) cost is caused by the pattern
- Questions useful for an evaluation:
- Usage
- Detect useful patterns (where and which pattern for a certain problem)
- Adaption of patterns to actual use case (not always 1:1 applicable)
- Pattern classification and names
-
Creational: Abstract an object creation process (make a system independent of the way its objects are created, composited or represented)
- Abstract factory: Families of objects without specifying the exact underlying classes
- Builder
- Factory Method: Creates an obj. without specifying the exact underlying class
- Prototype
- Singleton
-
Structural: Define how classes/objects are composited (mostly to create a greater structure)
- Adapter
- Bridge
- Decorator
- Facade
- Flyweight
- Composite
- Proxy
-
Behavioural: Communication and responsibilities between objects
- Command
- Observer
- Visitor
- Interpreter
- Iterator
- Memento
- Template Method
- Strategy
- Mediator
- State
- Chain of Responsibility
-
Creational: Abstract an object creation process (make a system independent of the way its objects are created, composited or represented)
- Relation between patterns (from easy to (complex + flexible)):
Factory Method -> Abstract Factory -> Prototype -> Builder
- Factory Method vs. Builder:
- Factory method is usually just a wrapper function where the entire object has will be created at once.
- For the builder (which is a wrapper object) it happens usually step-wise (esp. when the object cannot produced in one step (e.g. de-serialization process for a complex object)) - e.g. using setter methods to set/modify the creation behaviour
TODO: Show an example in C++ in as few lines of code as possible. With that example (potentially use comments) show the difference between tight coupling and loose coupling; use the newest C++ standard and best practices; use cars and/or car manufacturers as an example for meaningful class names; use maximum 10 lines of code for all if possible.
Y A G N I
o i o e t
u n n e
' n d
t a
=> Implement only what you need (don't try to predict the future in your implementation)
O C P
p l r
e o i
n s n
e c
i
p
l
e
- A class should be open for extension but closed to modification
- Derived classes should extend the base class(es) without changing their behaviour (-> Liskov Substitution Principle)
D R Y
o e o
n p u
' e r
t a s
t e
l
f
=> Generalise
S R P
i e r
n s i
g p n
l o c
e n i
s p
i l
b e
i
l
i
t
y
=> 1 class/function/... should only have one purpose
Dependency Inversion Principle:
High-level modules should not import anything from low-level modules. Both should depend on abstractions (e.g., interfaces). Abstractions should not depend on details. Details (concrete implementations) should depend on abstractions. (from: https://en.wikipedia.org/wiki/Dependency_inversion_principle)
Tight vs loose coupling:
// Tight Coupling
class BMW { public: void startBMW() {} };
class Driver1 { BMW car; public: void go() { car.startBMW(); } }; // Driver1 is tightly coupled with BMW (BMW might use other functions then a Mercedes => hard to maintain)
// Loose Coupling
class ICar { public: virtual void start() = 0; }; // Interface for Car (abstracts the all cars)
// pure virtual to force implementing the interface
class Ferrari : public ICar { void startFerrari() { /* ... */ } public: void start() override { startFerrari(); } }; // Implement start of ICar
class Driver2 {
ICar& car; // Use ICar instead of the actual car to make it independent of the manufacturer (-> loose coupling)
public:
Driver2(ICar& c) : car(c) {}
void go() { car.start(); }
};
class Mercedes : public ICar { void startMercedes() { /* ... */ } public: void start() override { startMercedes(); } };
Mercedes mercedes;
Driver2 driver2(mercedes); // Using Mercedes with Driver2
driver2.go(); // Start Mercedes
This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License *.
Code (snippets) are licensed under a MIT License *.
* Unless stated otherwise