GoF의 디자인 패턴, 가교 패턴에 대해 알아본다.
해당 글은, 다음의 코드를 기반으로 이해하는 것이 편리합니다.
이 두 계층 사이에 다리를 놓는 것과 같은 방식의 패턴을 가교 패턴이라 한다.
Draft
는 아직 출간되지 않은 글을 말함Draft
를 출력하기 위해 Display
interface를 채택하고 있는 구현체를 받음Draft
구현체는 이 Display
구현체에 요청하여 실질적으로 출력을 요청함Display
를 채택한 다른 구현체를 넣어버리면 됨 let draft = Draft(title: "비트코인은 무엇인가",
author: "최완식",
contents: ["사토시", "사카모토", "암호화폐"])
// 출력을 담당하는 구현체를 넣어줌
let simpleDisplay = SimpleDisplay()
// 실질적인 구현은 Display가 하고 있음
draft.describe(display: simpleDisplay)
// 다른 방식으로 출력하고 싶다면 다르게 구현한 녀석을 넣어주면 됨
let captionDisplay = CaptionDisplay()
draft.describe(display: captionDisplay)
Publication
객체는 Draft
를 상속받아 출판사, 가격을 가지고 있으며, 이를 출력해야 한다. // Publication
let publication = Publication(title: "나도 책 쓸 수 있다",
author: "최완식",
contents: ["야", "너도", "책 쓸 수 있어"],
publisher: "동아출판",
cost: 39000)
// display 객체도 재활용이 가능하다.
publication.describe(display: captionDisplay)
internal class Publication: Draft {
internal let publisher: String
internal let cost: Int
internal init(title: String,
author: String,
contents: [String],
publisher: String,
cost: Int) {
self.publisher = publisher
self.cost = cost
super.init(title: title,
author: author,
contents: contents)
}
private func describePublicationInfo() {
print("# \(self.publisher) $ \(cost)")
}
// 기본 Draft의 기능은 똑같이 유지하면서, 해당 클래스가 가지는
// 추가적인 특징만을 넣었음
internal override func describe(display: Display) {
super.describe(display: display)
self.describePublicationInfo()
}
}
Display
)이 여러가지 구현(SimpleDisplay
)으로 나올 경우 대부분은 상속을 사용한다.AWindow
, BWindow
, CWindow
를 만드는데는 큰 문제가 안생긴다.IconWindow
라는게 생겼다.A
, B
모두에서 사용가능해야 한다는 점을 깨달았다.IconWindow
이외에 다른 녀석들도 막 추가된다면 어떨까? 지옥이 시작된다.IconWindow
의 경우 Drawborder
라는 함수가 있는데, 이 실질 동작은WindowImp
의 구현체를 받아 처리하고 있다. 각 플랫폼에 맞는 구현체를 넣으면 끝나는 것이다.WindowImp
로 추상화하여 분리함으로서 유연성을 확보했다.Publication
이 생길 때, 다른 부분의 코드 변경이 없었음Document
): 추상적 개념에 대한 인터페이스 제공Draft
): 추상적 개념에 대한 인터페이스 구현Display
): 구현 클래스에 대한 인터페이스 제공SimpleDisplay
, CaptureDisplay
): Implementor 인터페이스 구현, 실질적인 구현 내용