Exist Technote

[Python] Adapter Pattern (어댑터 패턴) 본문

Design Pattern/Structural

[Python] Adapter Pattern (어댑터 패턴)

by_Exist 2020. 10. 5. 22:52

http://www.tmon.co.kr/deal/2034250634 광고 아닙니다. 많이 파세요...!

Adapter Pattern이란?

  • 호환성이 없는 인터페이스 때문에 함게 동작할 수 없는 클래스들이 함께 작동하도록 하는 패턴.
  • 클래스의 인터페이스를 사용자가 기대하는 다른 인터페이스로 변환하는 패턴.
  • 이미 만들어진 라이브러리를 수정하지 않고 인터페이스를 정의하고 싶을 때 사용되는 패턴.

예제

# 다른 인터페이스들을 지닌 여러 클래스.
class Dog:
    def __init__(self):
        self.name = "Dog"

    def bark(self):
        return "woof!"

class Cat:
    def __init__(self):
        self.name = "Cat"

    def meow(self):
        return "meow!"

class Human:
    def __init__(self):
        self.name = "Human"

    def speak(self):
        return "'hello'"

class Car:
    def __init__(self):
        self.name = "Car"

    def make_noise(self, octane_level):
        return f"vroom{'!' * octane_level}"

# 객체들의 인터페이스를 통합하는 어뎁터 클래스.
class Adapter:

    def __init__(self, obj, **adapted_methods):
        self.obj = obj
        self.__dict__.update(adapted_methods)

    # attr을 self에서 찾을 수 없을 때 호출되는 메서드.
    def __getattr__(self, attr):
        return getattr(self.obj, attr)

    def original_dict(self):
        return self.obj.__dict__


if __name__ == "__main__":

    dog = Dog()
    cat = Cat()
    human = Human()
    car = Car()

    objects = [
        Adapter(dog, make_noise=dog.bark),
        Adapter(cat, make_noise=cat.meow),
        Adapter(human, make_noise=human.speak),
        Adapter(car, make_noise=lambda: car.make_noise(3)),
    ]

    print('name' in objects[0].original_dict())
    print('make_noise' in objects[0].__dict__)

    # 단일 인터페이스로 활용되는 예제
    for obj in objects:
        print("A {0} goes {1}".format(obj.name, obj.make_noise()))

여담

  • 덕타이핑 방식으로 setattr()를 사용할 수도 있다.
class Test:

    def test1(self):
        return "test1"

test = Test()
setattr(test, 'test2', test.test1)
print(test.test2())
  • 디스크립터 또는 데코레이터로도 설계할 수 있지 않을까?
Comments