7.2. Adapter¶
EN: Adapter
PL: Adapter
Type: class and object
7.2.1. Pattern¶
Convert an interface of an object to a different form
Like power socket adapter for US and EU
Refactoring of a large application
Working with legacy code / database
Niekompatybilne API dwóch systemów
Wymagające różnych sposobów uwierzytelniania (OAuth2, BasicAuth)
Tłumaczenie pomiędzy różnymi formatami danych (SOAP/XML, REST/JSON)
Iteracyjne przepisywanie legacy systemu na nowy, ale tak, aby móc wciąż korzystać ze starego

7.2.2. Problem¶
BlackAndWhite3rdPartyFilter
is from external libraryDoes not conform to
Filter
interfaceDo not have
apply()
methodNeed manual call of
init()
at initializationNeed manual call of
render()

from abc import ABC, abstractmethod
from pathlib import Path
#%% 3rd Party
class AmazingFilter:
def __init__(self):
print('Setting up filter')
def transform(self, content: bytes) -> bytes:
print('Making your phot amazing')
return content
#%% Abstract
class Filter(ABC):
@abstractmethod
def apply(self, content: bytes) -> bytes:
...
#%% Implementation
class SepiaFilter(Filter):
def apply(self, content: bytes) -> bytes:
print('Making photo in sepia')
return content
class SharpenFilter(Filter):
def apply(self, content: bytes) -> bytes:
print('Making photo sharp')
return content
#%% Main
class Image:
path: Path
content: bytes
def __init__(self, path):
self.path = Path(path)
self.content = self.path.read_bytes()
def apply(self, filter: Filter) -> None:
self.content = filter.apply(self.content)
if __name__ == '__main__':
img = Image('/tmp/myfile.png')
img.apply(SepiaFilter())
img.apply(SharpenFilter())
img.apply(AmazingFilter())
# AttributeError: 'AmazingFilter' object has no attribute 'apply'
7.2.3. Solution¶
Inheritance is simpler
Composition is more flexible
Favor Composition over Inheritance

Figure 7.9. Please mind, that on Picture there is a Caramel
filter but in code BlackAndWhite3rdPartyFilter
¶
from abc import ABC, abstractmethod
from pathlib import Path
#%% 3rd Party
class AmazingFilter:
def __init__(self):
print('Setting up filter')
def transform(self, content: bytes) -> bytes:
print('Making your phot amazing')
return content
#%% Abstract
class Filter(ABC):
@abstractmethod
def apply(self, content: bytes) -> bytes:
...
#%% Implementation
class SepiaFilter(Filter):
def apply(self, content: bytes) -> bytes:
print('Making photo in sepia')
return content
class SharpenFilter(Filter):
def apply(self, content: bytes) -> bytes:
print('Making photo sharp')
return content
# %% Adapter
class AmazingFilterAdapter(Filter):
filter: AmazingFilter
def __init__(self):
self.filter = AmazingFilter()
def apply(self, content: bytes) -> bytes:
self.filter.__init__()
return self.filter.transform(content)
#%% Main
class Image:
path: Path
content: bytes
def __init__(self, path):
self.path = Path(path)
self.content = self.path.read_bytes()
def apply(self, filter: Filter) -> None:
self.content = filter.apply(self.content)
if __name__ == '__main__':
img = Image('/tmp/myfile.png')
img.apply(SepiaFilter())
img.apply(SharpenFilter())
img.apply(AmazingFilterAdapter())
7.2.4. Use Case - 0x01¶
>>> def otherrange(a, b, c): # function with bad API
... current = a
... result = []
... while current < b:
... result.append(current)
... current += c
... return result
>>>
>>>
>>> def myrange(start, stop, step): # adapter
... return otherrange(a=start, b=stop, c=step)
>>>
>>>
>>> myrange(start=10, stop=20, step=2)
[10, 12, 14, 16, 18]