From 8867ada688178a18d7b1a0935716b28b3a94f776 Mon Sep 17 00:00:00 2001 From: Erison Silva Date: Fri, 27 Sep 2024 13:24:39 +0200 Subject: [PATCH] New Post: Decorator pattern in open source code --- .../decorator-pattern-in-open-source-code.md | 136 ++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 src/content/blog/decorator-pattern-in-open-source-code.md diff --git a/src/content/blog/decorator-pattern-in-open-source-code.md b/src/content/blog/decorator-pattern-in-open-source-code.md new file mode 100644 index 0000000..0a9ed5a --- /dev/null +++ b/src/content/blog/decorator-pattern-in-open-source-code.md @@ -0,0 +1,136 @@ +--- +author: Erison Silva +pubDatetime: 2024-09-27T10:00:00Z +title: Decorator pattern in open source code +slug: decorator-pattern-in-open-source-code +featured: true +draft: false +tags: + - pattern + - developer +description: How Decorator pattern can help us modify some functionalities from open source code. +--- + +In some open source repositories that contain a **small** number of maintainers are common to see classes as final, it happens because they can make modification without complex *Backward Compatibility Promise*, But on the other hand it keeps code a bit "complicated" to modify! + +But well it is not so complicated since they implements interfaces and use *composition* in the code 😁, and here starts the beneficial of [Decorator pattern][decorator-pattern] 💅. + + +## Open source code + +I was looking for some project that has a good number of users, Then I choose [EasyAdminBundle][easy-admin-bundle] as example, it has more then **+18k users** and **4k starts** + +the piece of code that I gonna use is [AdminUrlGenerator.php][admin-url-generator], and we gonna add a dispatch event when the [generate method][admin-url-generator-method] is called. + +## Creating a decorator + +As the AdminUrlGenerator.php is a final class, it is not possible to extends this class and overite `generate` method, and in this case an alternative is use a decorator. + +```php +adminUrlGenerator->generate(); + $this->event->dispatch(new UrlGeneratedEvent($url)); + + return $url; + } + + public function setRoute(string $routeName, array $routeParameters = []): self + { + $this->adminUrlGenerator->setRoute($routeName, $routeParameters); + + return $this; + } + + public function get(string $paramName): mixed + { + return $this->adminUrlGenerator->get($paramName); + } + + //.... +} +``` + +## Breaking Down AdminUrlGeneratorDecorator class + +```php +adminUrlGenerator->generate(); + $this->event->dispatch(new UrlGeneratedEvent($url)); + + return $url; + } +``` + +It is the method that we want to modify, on the first line we are calling the original method to generate the url. +the second line is dispatching our event and in the last one we are returning the url generated by original method. + +```php +adminUrlGenerator->setRoute($routeName, $routeParameters); + + return $this; + } + + public function get(string $paramName): mixed + { + return $this->adminUrlGenerator->get($paramName); + } + + //.... +``` +Maybe you were asking yourself, "why do I need those methods if I just want to change `generate` method?" + +It is needed because [AdminContextProvider][admin-context-provider-interface] is forcing to implement those methods. +and this case we must implement them and call the original implementation, like I did with `setRoute` and `get` methods + +> Just to simplify the example I did not add all methods, But you must add all of them. + +[decorator-pattern]: https://refactoring.guru/design-patterns/decorator +[easy-admin-bundle]: https://github.com/EasyCorp/EasyAdminBundle +[admin-url-generator]: https://github.com/EasyCorp/EasyAdminBundle/blob/v4.12.0/src/Router/AdminUrlGenerator.php +[admin-url-generator-method]: https://github.com/EasyCorp/EasyAdminBundle/blob/v4.12.0/src/Router/AdminUrlGenerator.php#L261 +[admin-context-provider-interface]: https://github.com/EasyCorp/EasyAdminBundle/blob/v4.12.0/src/Router/AdminUrlGeneratorInterface.php#L10