65 lines
1.9 KiB
Markdown
65 lines
1.9 KiB
Markdown
|
---
|
||
|
title: >
|
||
|
The Decorator design pattern
|
||
|
pubDate: 2022-12-08
|
||
|
permalink: >-
|
||
|
archive/2022/12/08/the-decorator-design-pattern
|
||
|
tags:
|
||
|
- design-patterns
|
||
|
---
|
||
|
|
||
|
Decorator is a structural design pattern that allows you to add extra functionality, such as if you want to add caching or logging to a service, without changing the original class.
|
||
|
|
||
|
As long as a class implements an Interface, it can be decorated.
|
||
|
|
||
|
For example, if I have this PHP interface:
|
||
|
|
||
|
```php
|
||
|
interface DoesSomething
|
||
|
{
|
||
|
public function doSomething(): void;
|
||
|
}
|
||
|
```
|
||
|
|
||
|
I could have this class that does something:
|
||
|
|
||
|
```php
|
||
|
final class FirstClass implements DoesSomething
|
||
|
{
|
||
|
public function doSomething(): void
|
||
|
{
|
||
|
// Does something.
|
||
|
}
|
||
|
}
|
||
|
```
|
||
|
|
||
|
If I need to do something else, like caching or logging the result, I can decorate it.
|
||
|
|
||
|
To do this, I need another class that implements the same interface and inject the original version.
|
||
|
|
||
|
```php
|
||
|
final class SecondClass implements DoesSomething
|
||
|
{
|
||
|
public function __constuct(
|
||
|
private DoesSomething $originalClass
|
||
|
) {}
|
||
|
|
||
|
public function doSomething()
|
||
|
{
|
||
|
// Do something else before.
|
||
|
|
||
|
$this->originalClass->doSomething();
|
||
|
|
||
|
// Do something else afterwards.
|
||
|
}
|
||
|
}
|
||
|
```
|
||
|
|
||
|
Within the new class, the methods can be overridden, extra functionality can be added, and the original method can be run to execute the original functionality.
|
||
|
|
||
|
As the two classes implement the same interface, I can swap between different versions and decorate multiple times if needed.
|
||
|
|
||
|
This a pattern that I used recently to extend a service that retrieved some data from an API and saved it to a file, to change some arguments and do more work with it.
|
||
|
|
||
|
The original class was unchanged, the new class was minimal and easy to understand as it only had a single responsibility, and if I needed to switch back to the original version, I could easily do that.
|