- SOLID Principles
- UML Relations
- Design patterns
- Design Pattern Types
- Behavioral Design Patterns
- Structural Design Patterns
- Creational Design Patterns
SOLID is an acronym for five design principles that promote cleaner, more maintainable code. These principles are widely used in object-oriented programming (OOP).
- A class should have only one reason to change, meaning it should only have one job or responsibility.
- Example: A class that handles both database operations and business logic should be split into two classes, one for each responsibility.
- Software entities (classes, modules, functions, etc.) should be open for extension but closed for modification. This means you can add new functionality to a class without changing its existing code.
- Example: You can add new types of payment methods to a payment system without modifying the existing payment processing class, by extending it
- Objects of a superclass should be replaceable with objects of a subclass without affecting the correctness of the program.
- Example: If you have a Shape class and a Rectangle subclass, replacing an object of type Shape with a Rectangle should not cause any unexpected behavior or errors.
- Clients should not be forced to implement interfaces they do not use. In other words, it’s better to have several small, specific interfaces than a large, general one.
- Example: If a Printer interface has methods for both print() and fax(), but not all printers support faxing, you should split the interface into two: Printable and Faxable.
- High-level modules should not depend on low-level modules. Both should depend on abstractions (e.g., interfaces or abstract classes). Additionally, abstractions should not depend on details; details should depend on abstractions.
- Example: Instead of directly instantiating objects inside a class (e.g., new DatabaseConnection()), use dependency injection to pass an abstraction (e.g., an interface for DatabaseConnection) to the class.
- Concept: Avoid duplicating code. If you notice the same logic is used in multiple places, refactor it into a single reusable module or function.
- Example: Instead of writing the same validation code for email in multiple classes, create a separate utility function that handles email validation.
- Concept: Keep your software design as simple as possible. Avoid overcomplicating solutions when a simpler one would suffice.
- Example: If you can solve a problem with a basic loop and conditional statement, don’t over-engineer it with unnecessary complexity like recursion or multiple design patterns.
- Concept: Don’t add functionality unless it’s absolutely necessary. Avoid building features that might be useful in the future but are not required at the moment.
- Example: Don’t implement an admin panel if you don’t currently need it, just because you think you might in the future.
- Concept: Favor object composition over inheritance. Inheritance can create tight coupling between classes, while composition allows for greater flexibility by allowing objects to delegate tasks to other objects.
- Example: Instead of creating a Car class that inherits from a Vehicle class, compose a Car class with a Engine and Wheels objects.
- Definition: A relationship where one class depends on another for its operation or behavior.
- Example: A
Printer
class depends on thePaper
class.
- Definition: A structural relationship that represents how objects are connected to each other.
- Example: A
Teacher
teachesStudents
.
- Definition: A "whole-part" relationship where the part can exist independently of the whole.
- Example: A
Classroom
hasStudents
, butStudents
can exist without theClassroom
.
- Definition: A stronger form of aggregation where the parts cannot exist without the whole. If the whole is destroyed, the parts are destroyed too.
- Example: A
House
containsRooms
, and if the house is demolished, the rooms no longer exist.
- Definition: A relationship where one class (subclass) inherits from another class (superclass).
- Example: A
Car
is a type ofVehicle
.
- Definition: A relationship between an interface and a class that implements the interface.
- Example: A
Dog
class implements theAnimal
interface.
In software engineering, a design pattern is a general repeatable solution to a commonly occurring problem in software design. A design pattern isn't a finished design that can be transformed directly into code. It is a description or template for how to solve a problem that can be used in many different situations. In addition, design patterns allow developers to communicate using well-known, well understood names for software interactions.
Design patterns can be separated into three main categories:
- Behavioral : Behavioral patterns are concerned with algorithms and the assignment of responsibilities between objects. Behavioral patterns describe not just the patterns of objects or classes but also the patterns of communication between them.
- Structural : Structural design patterns are design patterns that ease the design by identifying a simple way to realize relationships among entities. Structural patterns are concerned with how classes and objects are composed to form larger structures.
- Creational : Creational design patterns are design patterns that deal with object creation mechanisms, trying to create objects in a manner suitable to the situation. The basic form of object creation could result in design problems or added complexity to the design. Creational design patterns solve this problem by somehow controlling this object creation.
Behavioral design patterns focus on how objects interact and communicate with each other. They define the responsibilities and relationships between objects, ensuring that complex interactions are managed efficiently while promoting loose coupling. (Ils définissent comment les objets interagissent et communiquent entre eux pour gérer efficacement les responsabilités et les relations.)
Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.
Example :
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 :
Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations.
Example :
Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation.
Define an object that encapsulates how a set of objects interact. Mediator promotes loose coupling by keeping objects from referring to each other explicitly, and it lets you vary their interaction independently.
Without violating encapsulation, capture and externalize an object's internal state so that the object can be restored to this state later.
Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.
Allow an object to alter its behavior when its internal state changes. The object will appear to change its class.
Define the skeleton of an algorithm in the superclass but let subclasses override specific steps of the algorithm without changing its structure.
Represent an operation to be performed on the elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates
Convert the interface of a class into another interface clients expect. Adapter lets classes work together that couldn't otherwise because of incompatible interfaces.
Provide a surrogate or placeholder for another object to control access to it.
Decouple an abstraction from its implementation so that the two can vary independently.
Compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly.
Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.
Example :
Ensure a class only has one instance, and provide a global point of access to it.
The Factory Method Pattern is a creational design pattern that provides an interface for creating objects, but allows subclasses to alter the type of objects that will be created.
Provide an interface for creating familiesof related or dependent objects without specifying their concrete classes.
Separate the construction of a complex object from its representation so that the same construction process can create different representations.