@SmaineDev
@SmaineDev
💡Common Patterns - 🗜️How to? - 🗺️ Real Examples
@SmaineDev
🛠️ Creational
How to create objects efficiently
🏗️ Structural
How to combine objects to build flexible and bigger systems
💬 Behavioral
How objects talk and work together
@SmaineDev
Change the behavior without modifying the code — simply by switching strategies.
@SmaineDev
@SmaineDev
🧩Defines a family of algorithms that are interchangeable
⚙️Allows dynamic selection of the algorithm at runtime
✏️Eliminates large conditional blocks (if/else
, switch
)
🍄Promotes flexibility and extensibility in the code
@SmaineDev
🎥 replay
Makes two incompatible interfaces work together by using an adapter object that translates the calls.
🔌 European plugs
🔌 US plugs
@SmaineDev
Database
@SmaineDev
Makes two incompatible interfaces work together by using an adapter object that translates the calls.
Replace a DoctrineRepository with an HttpRepository
Messenger 📬
DoctrineTransport, AmqpTransport, InMemoryTransport...
Mailer 📨
SendmailTransport, SmtpTransport, EsmtpTransport...
@SmaineDev
🤝Bridge incompatible interfaces
👝 Reuse legacy/external code
🧲 Enable a unified contract
💅 Simplify dependency swapping
Create an object depending of a context or an environment
@SmaineDev
🗣️ We use an external provider but we don't want to rely on it
in local/staging/ci environment
Create an object without worrying about its internal construction.
📦 Pass the form type and options to the factory.
🎯Factory decides which concrete class to create and how to hydrate it with extensions, child types...
✅ Get a ready-to-use object without worrying about its internal construction.
@SmaineDev
🔨 Encapsulate object creation logic
🎛️ Provide a unified way to instantiate objects
🌀 Enable polymorphism without new
everywhere
🔄 Simplify swapping implementations
@SmaineDev
Create a complex objects step by step, depending of options and/or configuration
@SmaineDev
Build an object step by step
💡Construct complex objects step by step without huge constructors.
🤓 Objects with many optional fields or configurations.
✅ Separate construction from representation.
An intermediary object between a client and a target object, in order to control or add behavior when accessing that object.
💤 Lazy loading
🗃️ Caching
🚔 Access control
🪞Proxy creation
Inherits from your entity
Adds an __initializer__
(closure)
Contains the ID and minimal metadata
🕸️Access Interception
Overridden methods (getters...
)
Calls the __initializer__
if the object isn’t loaded yet
👋🏽 On Demand loading
The initializer calls Doctrine’s UnitOfWork
→ targeted SQL
Hydrates the full object
✅ Object initialized
The initializer is set to null
The object now behaves like a normal entity
Doctrine doesn’t give you your entity directly → it gives you a proxy subclass that only loads the data when you actually need it.
🧚♂️Avoids unnecessary SQL queries
🤖Automatically handles lazy
relationships
🔬Transparent to the developer
🛡 Access control: intercept calls to enforce permissions, authentication, or rules before delegating to the real object.
⚡ Lazy loading: delay the creation of a heavy object or connection (e.g., database, remote API) until it’s actually needed.
🔍 Monitoring / Logging: add logging, metrics, or performance monitoring around calls without modifying the target class.
🧹 Resource management: handle opening/closing connections, caching, or cleanup after using the real object.
When a user register, I need to :
Generate an invoice
Decrease the available capacity
Send a confirmation email
Send a Slack notification
Update the database
Log the registration event
Trigger marketing automation
...
A Subject notify the observers that an event occurs
OBSERVER #1
OBSERVER #2
notify($obj)
handle($obj)
handle($obj)
OBSERVER #3
handle($obj)
Observer (classic)
Event Dispatcher
🪢 Coupling
The Observer
often knows the Subject
directly or its interface → stronger coupling.
Loose coopling,
Listeners don't know the emitter
🚠 Event
handling
Simpler, often custom-coded
Advanced: propagation, priority, named events.
🗺️ Extensibility
Rich system (dynamic add/remove listeners...)
Basic: just a notification and sometimes a state.
kernel.controller
kernel.exception
kernel.request
kernel.view
kernel.response
kernel.terminate
console.command
form.pre_submit
...
prePersist
postPersist
preUpdate
postUpdate
preRemove
postRemove
...
Design Patterns, le trésor est dans le vendor
@SmaineDev
@SmaineDev
@SmaineDev
🤕 Docx mimetype is often not well detected by Symfony validator
😡 Customers complains because their docx cannot be used
The mimetype of a Docx can be:
✅application/vnd.openxmlformats[...].document
❌null
❌application/octet-stream
❌application/zip
@SmaineDev
Dynamically add new behavior to an object
without modifying its original class, by wrapping it
in another object that implements the same interface.
The mimetype of a Docx can be:
✅ application/vnd.openxmlformats[..].document ❓ null => Decorator 🎁
❓ application/octet-stream => Decorator 🎁
❓ application/zip => Decorator 🎁
Decorate the Symfony MimeTypeGuesser to inspect the document if it's a real docx
⏏️ Upload
🗃️ Storage
📄 Conversion
class DocxUploaderConverter
{
public function uploadAndConvert(File $docxFile): File
{
//... 🍯 Tambouille
1️⃣ Upload
2️⃣ Storage
3️⃣ Conversion
return $pdfFile;
}
}
🎯 Goal: Provide a simplified and unified interface to a complex subsystem.
🤝 Hides the internal complexity of multiple services/objects.
🚪 The client only uses one entry point, without knowing the details.
✅ Benefits: easier usage, reduced coupling, improved readability.
💡Facades in Symfony provide one simple entry point for developers, hiding dozens of internal services, adapters, and configurations behind a clean API.
🎯 Goal: Define a fixed workflow
while letting subclasses customize certain steps.
Each command has its own behavior but follows the same workflow (initialize → interact → __invoke/execute).
The Chain of Responsibility pattern lets a request pass through a chain of handlers, and the first handler that can handle it does. It decouples the sender from the receiver.
source: https://refactoring.guru/design-patterns/chain-of-responsibility
Serialize
Deserialize
💡The serializer doesn’t normalize/denormalize by itself.
🔁 It loops through available normalizers.
❓It asks each one: “Do you support this data?”
🙋🏿♂️ The first normalizer that says yes handles the data.
@SmaineDev
Design Patterns List ⏭️
A single global instance
Singleton
Factory
Delegate creation
Builder
Construction of an object step by step
Prototype
Create an object by copying an existing one
Bridge
Separate abstraction from implementation
Composite
Hierarchical tree structures
Facade
Simplified Interface
Convert Interface into another one
Adapter
Flyweight
Sharing objects to save memory
Proxy
Surrogate or access control
Strategy
Interchangeable algorithms
Observer
Automatic notification
Template
Skeleton of an algorithm
Pass the request along a chain
Chain of responsability
Iterator
Sequential traversal
Memento
Save and restore state
Mediator
Centralize communication
State
Change behavior base on state
Visitor
New operations without modifying structure
Mediator
Centralize communication
Command
Encapsulate a request
Mediator
Centralize communication