Пример №1
Бытовой пример реализации паттерна адаптер. Предположим у нас есть:
- Розетка американского типа (usa), которая имеет два плоских параллельных между собой контакта. (рис. 1)
- Чайник с вилкой подходящей к американской розетке (рис.2)
- Утюг который имеет вилку европейского образца. (рис. 3)
Очевидно, что мы не сможем воткнуть евроровилку (рис. 3) в американскую розетку (рис. 1), для этого нужен переходник.
# Американская вилка class UsaFork: def power_usa(self): print('power on. Usa') # Европейская вилка class EuroFork: def power_euro(self): print('power on. Euro') # Американская розетка class UsaSocket: def __init__(self, fork): self.fork = fork def connect(self): self.fork.power_usa() # Вставляем американскую вилку в американскую розетку. uf = UsaFork() us = UsaSocket(uf) us.connect() # >>> power on. Usa # При попытке вставить европейскую вилку в американскую розетку, будет ошибка ef = EuroFork() us = UsaSocket(ef) us.connect() # >>> AttributeError: 'EuroFork' object has no attribute 'power_usa'
Обратите внимание, что метода розетки «connect» внутри вызывает метод «power_usa()» — который есть только у американской розетки.
Создадим адаптер переходник, с помощью него мы подключимся к американской розетке
class AdapterEuroInUsa: def __init__(self): self._euro_fork = EuroFork() def power_usa(self): self._euro_fork.power_euro()
В адаптере мы создаем метод power_usa() — такой-же как у американской розетки(UsaFork), но реализация этого метода будет от класса европейской вилки. (EuroFork)
Получаем
# Вставляем американскую вилку в американскую розетку. uf = UsaFork() us = UsaSocket(uf) us.connect() # >>> power on. Usa # Вставляем евро-адаптер в американскую розетку. ad = AdapterEuroInUsa() us = UsaSocket(ad) us.connect() # >>> power on. Euro
Получается, что благодаря адаптеру мы можем использовать интерфейс класса `UsaFork`, а реализацию класса `EuroFork`.
Пример №2
Допустим у нас есть система которая работает с текстом, что-то там парсит, чистит, формирует.
Так-же у нас есть вторая система которая способна быстро и очень эффективно подсчитывать частотности слов в любом тексте.
Важно понимать, что это 2 не зависимые между собой системы.
Представим их в виде классов:
# Система №1 class System: # Класс, представляющий систему def __init__(self, text): tmp = re.sub(r'\W', ' ', text.lower()) tmp = re.sub(r' +', ' ', tmp).strip() self.text = tmp def get_processed_text(self, processor): # Метод, требующий на вход класс-обработчик result = processor.process_text(self.text) # Вызов метода обработчика print(*result, sep='\n')
# Система №2 class WordCounter: # Обработчик, несовместимый с основной системой def count_words(self, text): self.__words = dict() for word in text.split(): self.__words[word] = self.__words.get(word, 0) + 1 def get_count(self, word): return self.__words.get(word, 0) def get_all_words(self): return self.__words.copy()
Итак, мы хотим что бы система №1 могла выводить текст в порядке частотности слов, используя при этом мега эффективный метод подсчета из системы №2. Для этого создадим специальный адаптер:
class WordCounterAdapter(TextProcessor): # Адаптер к обработчику def __init__(self, adaptee): # В конструкторе указывается, к какому объекту следует подключить адаптер self.adaptee = adaptee def process_text(self, text): # Реализация интерфейса обработчика, требуемого системой. self.adaptee.count_words(text) words = self.adaptee.get_all_words().keys() return sorted(words, key=lambda x: self.adaptee.get_count(x), reverse=True)
Итак, как все это будет работать.
Адаптер при инициализации принимает в качестве аргумента экземпляр системы №2 (WordCounter).
Далее в методе process_text() с помощью супер эффективных методов экземпляра класса системы №2 (WordCounter)
вычисляется частотность всех слов в тексте, а после результат сортируется.
Теперь нам необходимо передать этот адаптер системе №1 (class System).
Для этого у системы №1 есть метод, который в качестве параметра принимает экземпляр класса адаптер, в нашем примере это переменная «processor»:
def get_processed_text(self, processor): # Метод, требующий на вход класс-обработчик result = processor.process_text(self.text) # Вызов метода обработчика print(*result, sep='\n')
В итоге связка работает так:
text = 'la bla la la text test' system_one = System(text) system_two = WordCounter() adapter_one_two = WordCounterAdapter(system_two) system_one.get_processed_text(adapter_one_two)