Created
September 1, 2021 12:38
-
-
Save seppeljordan/8051320d997be506ed585270c44e101b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from __future__ import annotations | |
from abc import ABC, abstractmethod | |
from functools import lru_cache | |
from typing import List | |
cache = lru_cache() | |
class WorkDoer: | |
def __init__(self, mail_sender: MailSender): | |
self.mail_sender = mail_sender | |
def do_work(self) -> None: | |
print("work done") | |
self.mail_sender.send_mail("work done") | |
class Logger: | |
def __init__(self, level: int): | |
print("instantiated logger") | |
self.level = level | |
def log(self, message: str) -> None: | |
if self.level > 1: | |
print(f"log: {message}") | |
def get_logger_config() -> int: | |
return 2 | |
class MailSender(ABC): | |
@abstractmethod | |
def send_mail(self, message: str) -> None: | |
pass | |
class TestMailSender(MailSender): | |
def __init__(self) -> None: | |
self.sent_mails: List[str] = [] | |
def send_mail(self, message: str) -> None: | |
self.sent_mails.append(message) | |
def get_sent_mails(self) -> List[str]: | |
return self.sent_mails | |
class DependencyInjector(ABC): | |
# since the following function call is cached, the logger is | |
# functionally a singleton. | |
@cache | |
def get_logger(self) -> Logger: | |
return Logger(self.get_logger_configuration()) | |
def get_logger_configuration(self) -> int: | |
return get_logger_config() | |
@abstractmethod | |
def get_mail_sender(self) -> MailSender: | |
pass | |
def get_work_doer(self) -> WorkDoer: | |
return WorkDoer(self.get_mail_sender()) | |
class TestDependencyInjector(DependencyInjector): | |
@cache | |
def get_test_mail_sender(self) -> TestMailSender: | |
return TestMailSender() | |
def get_mail_sender(self) -> MailSender: | |
return self.get_test_mail_sender() | |
# in your tests: | |
injector = TestDependencyInjector() | |
work_doer = injector.get_work_doer() | |
work_doer.do_work() | |
# The following won't actually work but is instead intended as an | |
# illustration as one would go about using DI in django. | |
class DjangoDependencyInjector(DependencyInjector): | |
def get_mail_sender(self) -> MailSender: | |
return TestMailSender() | |
def injection_view(view): | |
def wrapped_view(request, **kwargs): | |
injector = DjangoDependencyInjector() | |
return view(request, injector, **kwargs) | |
return wrapped_view | |
@injection_view | |
def do_work_view(request, dep_injector: DependencyInjector): | |
work_doer = dep_injector.get_work_doer() | |
work_doer.do_work() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi @seppeljordan, I followed up on our lecture and played with your code to get the hang of it. Next stop: injector
If you like, you can give me comments on my changes, here in this gist or next week in our meeting - I mainly:
logs
andsent_mails
[1] [2]@cache
to@singleton
because IMO this better reflects its purposeFun fact, I was thinking to myself "yeah, and after you made all those changes you have to adjust the Django example because it will most definately be broken somehow". I did not have to change a single thing 🥳
Code: