structural design pattern : 클래스 간 구조/관계를 정의하는 패턴
Adapter Pattern
하나의 인터페이스를 다른 인터페이스로 전환하는 역할
-> 이러한 역할을 Adapter Pattern에도 적용
'이미 제공되어 있는 것'과 '필요한 것' 사이의 차이를 없애주는 디자인 패턴을 Adapter Pattern이라고 함.
ex) 교류 110볼트 콘센트 ~ Adapter ~ 직류 12볼트의 노트북
Adapter Pattern 은 Wrapper Pattern 으로 불리기도함
Wrapper 는 '감싸는 것'이라는 의미가 있는데
무엇가를 포장해서 다른 용도로 사용할 수 있게 교환해주는 것이 wrapper이며, adapter 라고 함
두 가지의 종류
- 클래스에 의한 Adapter Pattern(상속하는 방법)
- 인스턴스에 의한 Adapter Pattern(위임하는 방법)
Adapter Pattern : 예시
목적 : Banner 클래스를 사용해서 Print 인터페이스를 충족시키는 클래스를 만드는 것
전원의 비유 | 예제 프로그램 | |
제공되고 있는 것(adaptee) | 교류 100볼트 | Banner 클래스 |
교환 장치(adapter) | 어댑터 | PrintBanner 클래스 |
필요한 것(target) | 직류 12볼트 | Print 인터페이스(printWeak, printStrong) |
Banner클래스 (제공되고 있는 것)
-문자열을 괄호로 묶어서 표시하는 showWithParen 메소드
- * 를 붙여 표시하는 showWithAster메소드
Print 클래스 (필요한 것)
-문자열을 느슨하게 표시하기 위한 printWeak 메소드
-문자열을 강하게 표시하기 위한 printStrong 메소드
PrintBanner 클래스 (교환 장치)
-제공되어 있는 Banner클래스를 상속해서, 필요로 하는 Print 인터페이스를 구현
- showWithParen 메소드를 사용해서 printWeak를 구현하고,
- showWithAster 메소드를 사용해서 printStrong을 구현 하고자 함
class Banner():
def __init__(self, word):
self.word = word
def showWithParen(self):
print("(" + self.word+")")
def showWithAster(self):
print("*"+ self.word+"*")
class Print():
def printWeak(self):
pass
def printStrong(self):
pass
#상속
class PrintBanner1(Banner,Print):
def __init__(self, word):
#현재 클래스가 어떤 클래스 인지 명확히 표기
super(PrintBanner1, self).__init__(word)
def printWeak(self):
self.showWithParen()
def printStrong(self):
self.showWithAster()
#위임
class PrintBanner2(Print):
def __init__(self, word):
#현재 클래스가 어떤 클래스 인지 명확히 표기
self.banner = Banner(word)
def printWeak(self):
self.banner.showWithParen()
def printStrong(self):
self.banner.showWithAster()
pb = PrintBanner1("hello")
pb.printStrong()
pb.printWeak()
#result : *hello*
# (hello)
pb = PrintBanner2("hello")
pb.printStrong()
pb.printWeak()
#result : *hello*
# (hello)
Adapter Pattern : 다른 예시
• Base class : Animal -> walk interface 가지고 있음
• Animal을 상속받은 Cat과 Dog class 모두 walk interface 가지고 있음
• makeWalk 함수는 animal을 argument로 갖고 Animal class의 walk 함수를 부를 수 있음
class Animal: #target
def walk(self):
pass
class Cat(Animal):
def walk(self):
print("cat walking")
class Dog(Animal):
def walk(self):
print("dog walking")
def makewalk(animal:Animal): #clicent
animal.walk()
kitty = Cat()
bingo = Dog()
makewalk(kitty)
makewalk(bingo)
#result : cat walking
# dog walking
Kitty와 bingo는 각각 Cat과 Dog object이며
makeWalk를 통해 walk함수를 실행시킬 수 있음
위와 이어지는 두번 째 예시
class Fish:
def swim(self):
print("fish swimming")
nemo = Fish()
makewalk(nemo)
Fish class는 swim interface만 있음
Fish class의 nemo object를 만들어서 makeWalk 함수로 넘겨주면 Error 발생
AttributeError: 'Fish' object has no attribute 'walk'
Fish class의 Object가 makeWalk interface를 사용하기 위해서는
Fish와 Animal interface를 연결시켜주는 Adapter가 있어야 함
class FishAdapter(Animal):
def __init__(self, fish:Fish):
self.fish = fish
def walk(self):
self.fish.swim()
nemo = Fish()
adapted_nemo = FishAdapter(nemo)
makewalk(adapted_nemo)
#result : fish swimming
그래서 FishAdapter 를 만들어줌.
FishAdapter class는 Animal을 상속받고 constructor 안에서 Fish object를 받음
• Nemo는 Fish Object이고 adapted_nemo는 FishAdapter에 nemo를 넘겨줌
• MakeWalk에 adapted_nemo를 넘겨주면 Fish의 Swim interface를 FIshAdapter의 walk를 통해 불러냄
Adapter pattern은 맞지 않는 기존의 interface를 현 재 코드에 맞게 변환시켜주는 역할을 함