how to apply Decorator design pattern with rodi?
Hi, How to apply the Decorator design pattern with rodi, on single instance registrations and/or collection registrations?
Example how I used to do it with a DI container from C# .Net called SimpleInjector (if same syntax were to be in lagom):
class HttpClient(ABC):
async def send(self, request: Request) -> Response:
pass
class ActualHttpClient(HttpClient):
async def send(self, request: Request) -> Response:
# Implement actual request send, e.g. with aiohttp
class LoggingHttpClientDecorator(HttpClient):
def __init__(self, decoratee: HttpClient):
self.__decoratee = decoratee
async def send(self, request: Request) -> Response:
print("Sending request")
response = await self.__decoratee.send(request);
print("Received response")
return response;
container = Container()
container[HttpClient] = Singleton(ActualHttpClient)
container.RegisterSingletonDecorator[HttpClient, LoggingHttpClientDecorator](); # mimics the SimpleInjector syntax
With this code, resolving HttpClient would return LoggingHttpClientDecorator decorating ActualHttpClient.
SimpleInjector also supports collection injections, e.g. injecting something like Iterable[EventHandler], and apply a decorator to all of the EventHandler instances registered to the collection.
Hi,
I apologize for taking so long to reply. The feature you describe looks interesting, it is not supported by rodi. It could be a nice addition to the library.
The closest you could get at the moment, is to use a factory:
from abc import ABC
from rodi import Container
class Base(ABC):
pass
class ActualImplementation(Base):
pass
class LoggingImplementation(Base):
def __init__(self, decoratee: Base) -> None:
super().__init__()
self._decoratee = decoratee
container = Container()
def example_factory() -> Base:
return LoggingImplementation(ActualImplementation())
container.add_singleton_by_factory(example_factory)
provider = container.build_provider()
example = provider.get(Base)
assert isinstance(example, LoggingImplementation)
assert isinstance(example._decoratee, ActualImplementation)
But I see the difference, since the decorator feature you are describing enables changing services that might be registered in a different package. In fact, it seems that the decorator might bypass completely the base class?
The decorator must have a constructor parameter implementing the same ABC as it's registered for, and can ignore it in the implementation of the abstract methods. The useful thing about such a decorator feature is the decorator may have other injectables other than the decoratee, e.g. LoggingImplementation can have a Logger dependency besides the decoratee, and the DI container would handle injection of additional dependencies for the user.
בתאריך יום ד׳, 1 בספט׳ 2021 ב-23:47 מאת Roberto Prevato < @.***>:
Hi, I apologize for taking so long to reply. The feature you describe looks interesting, it is not supported by rodi. It could be a nice addition to the library.
The closest you could get at the moment, is to use a factory:
from abc import ABC from rodi import Container
class Base(ABC): pass
class ActualImplementation(Base): pass
class LoggingImplementation(Base): def init(self, decoratee: Base) -> None: super().init() self._decoratee = decoratee
container = Container()
def example_factory() -> Base: return LoggingImplementation(ActualImplementation())
container.add_singleton_by_factory(example_factory) provider = container.build_provider() example = provider.get(Base) assert isinstance(example, LoggingImplementation)assert isinstance(example._decoratee, ActualImplementation)
But I see the difference, since the decorator feature you are describing enables changing services that might be registered in a different package. In fact, it seems that the decorator might bypass completely the base class?
— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/Neoteroi/rodi/issues/15#issuecomment-910733610, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABIFRN2USOQZROSMVYOQB73T72GPVANCNFSM5DAMYBDA . Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.
Thanks for opening this issue, I will keep it open and try to add this feature to the library (eventual contributions are welcome). This month I won't have much time for my open source projects, and I have pending things on the web framework, but I won't forget about this.
Thank you!
בתאריך יום ה׳, 2 בספט׳ 2021 ב-0:22 מאת Roberto Prevato < @.***>:
Thanks for opening this issue, I will keep it open and try to add this feature to the library (eventual contributions are welcome). This month I won't have much time for my open source projects, and I have pending things on the web framework, but I won't forget about this.
— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/Neoteroi/rodi/issues/15#issuecomment-910772089, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABIFRN7PSAEU7EVQEKULCF3T72KRFANCNFSM5DAMYBDA . Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.