안녕하세요 홍성호 입니다.
요즘 Java 언어로 배우는 디자인 패턴 입문 책으로 사내 스터디에 참여중 입니다.
https://book.naver.com/bookdb/book_detail.nhn?bid=4529127
평소에도 발표한다고 생각하고 스터디를 준비했었지만, 이번에는 진짜 발표를 하는거라 더 신경쓰이네요.
여러 각도에서 패턴을 살펴보겠습니다.
Bridge 패턴
'기능의 클래스 계층'과 '구현의 클래스 계층' 사이에 다리를 놓는 패턴이라고 소개되고 있습니다.
이 정의가 무슨말인지 한번에 이해가 되지 않았습니다 😭😭😭
제가 지식이 부족해서 그럴 수도 있지만, 책의 정의가 직관적이지 않다고 생각합니다.
이 글을 쓰면서 좀 더 좋은 정의를 찾아보겠습니다.
풀고싶은 문제
책의 예제를 조금 응용해서 전광판을 한번 만들어보겠습니다.
요구사항 1: 다양한 화면에서 보여주고 싶어요
이 전광판은 흑백 디스플레이에서 보여줄 수 있고, 컬러 디스플레이에서도 작동할 수 있으면 좋겠습니다.
더 나아가 미래의 어떤 장치로도 출력 가능하도록 만들고 싶습니다.
점자 디스플레이가 될 수도 있고, 3D 디스플레이가 될 수도 있겠네요.
요구사항 2: 깜빡 거리는 기능을 추가하고 싶어요
사람들의 눈에 띄도록 깜빡 거리는 전광판도 있으면 좋겠어요.
물론 흑백, 컬러 다 지원되어야 하죠.
해결책
글자를 보여줄 화면의 종류는 무한대로 늘어날 수도 있습니다.
화면을 추가할 때마다 정해진 틀 없이 코드를 작성 한다면 유지보수하기 너무 어려울 것 입니다.
이것을 해결하기 위해서 화면을 추상화 해보겠습니다.
프로토콜이나 추상 클래스로 추상화할 수 있습니다.
추상화된 틀을 가진 조작 기기는 여러 객체로 교체 가능합니다!
그러면 깜빡 거리는 기능을 추가하는 요구사항은 어떻게 해결할까요?
깜빡 거리는 기능을 추가하는 것은 무한대로 늘어나는 것은 아니며 기존 기능을 살려서 추가 구현할 계획입니다.
전광판 객체를 상속받아서 구현할 계획입니다.
상속 받아서 구현한다면
브릿지 패턴 사용해서 구현한다면
코드로 구현해보기
디스플레이를 추상화한 프로토콜 입니다.
protocol Display {
func on()
func off()
}
흑백으로 글자를 표시하는 디스플레이 입니다.
final class GrayScaleDisplay: Display {
private let text: String
private let label: UILabel
init(text: String, label: UILabel) {
self.text = text
self.label = label
}
func on() {
label.attributedText = NSAttributedString(string: text, attributes: [
.font: UIFont.boldSystemFont(ofSize: 30),
.foregroundColor: UIColor.systemGray
])
}
func off() {
label.attributedText = NSAttributedString(string: text.map { _ in "." }.joined(), attributes: [
.font: UIFont.boldSystemFont(ofSize: 30),
.foregroundColor: UIColor.black
])
}
}
랜덤 컬러로 글자를 표시하는 디스플레이 입니다.
final class ColorDisplay: Display {
private let text: String
private let label: UILabel
init(text: String, label: UILabel) {
self.text = text
self.label = label
}
func on() {
label.attributedText = NSAttributedString(string: text, attributes: [
.font: UIFont.boldSystemFont(ofSize: 30),
.foregroundColor: UIColor(
red: .random(in: 0...1),
green: .random(in: 0...1),
blue: .random(in: 0...1),
alpha: 1.0
)
])
}
func off() {
label.attributedText = NSAttributedString(string: text.map { _ in "." }.joined(), attributes: [
.font: UIFont.boldSystemFont(ofSize: 30),
.foregroundColor: UIColor.black
])
}
}
전광판 로직을 객체로 만들었습니다.
Display 객체를 받아서 단순히 on/off 만 실행하고 있습니다.
class PlainAD {
private let display: Display
init(display: Display) {
self.display = display
}
func start() {
display.on()
}
func end() {
display.off()
}
}
깜빡거리는 기능이 추가된 전광판 입니다.
타이머를 포함하고 있어서 일정 시간 반복하며 깜빡거립니다.
final class FlickerAD: PlainAD {
private var timer: DispatchSourceTimer?
func startFlicker() {
timer = DispatchSource.makeTimerSource(queue: .global())
timer?.schedule(deadline: .now(), repeating: .seconds(1))
var isOn: Bool = false
timer?.setEventHandler(handler: { [weak self] in
DispatchQueue.main.async {
if isOn {
self?.end()
} else {
self?.start()
}
isOn.toggle()
}
})
timer?.resume()
}
func endFlicker() {
timer?.cancel()
timer = nil
end()
}
}
실행하는 부분은 다음과 같습니다.
@objc
private func didTouchStartButton() {
plainGrayAD.start()
plainColorAD.start()
flickerGrayAD.startFlicker()
flickerColorAD.startFlicker()
}
@objc
private func didTouchEndButton() {
plainGrayAD.end()
plainColorAD.end()
flickerGrayAD.endFlicker()
flickerColorAD.endFlicker()
}
요구사항대로 잘 실행됩니다!!
https://github.com/cozzin/DesignPattern/tree/main/DesignPattern/Bridge
용어 정리
기능의 클래스 계층
함수안에 어떤 동작을 하면 기능하는 것이라고 볼 수 있을텐데 너무 범용적인 말이라고 생각합니다ㅠ
예제에서는 기본 절차를 구현해두고 추가적인 절차가 있을 때 객체를 상속 받아서 구현하고 있습니다.
기본 절차 및 추가적인 절차 구현 이라고 볼 수 있습니다.
부모 객체에 강한 종속을 갖기 때문에 확장은 제한적 입니다.
구현의 클래스 계층
구현이라는 말도 애매한데요.
위에서 본 예제의 Display가 속해 있는 계층이 이곳입니다.
정해진 틀을 지키면 무한대로 확장이 일어날 수 있는 것을 이 계층에 담습니다.
추상화 가능한 것을 나눈 계층 이라고 볼 수 있습니다.
생각 정리
- 정의를 좀 더 잘 해보고 싶었는데 여전히 복잡한 것 같습니다...
- 이해 못한 것: 왜 구현의 클래스 계층이라고 정의했는지 잘모르겠음
- 장점으로 생각되는 것: 상속할 부분과 위임할 부분을 구분해서 사용할 수 있습니다.
- 단점으로 생각되는 것: 두 계층 사이의 Mediator 객체가 따로 있는게 아니라서 브릿지라는 메타포가 쉽게 떠오르지 않습니다ㅠ
토론 거리
- iOS에 브릿지패턴이 적용된게 있을지
- iOS 프레임워크 자체에 적용된건 떠오르는게 없음
- 공유하기 기능에 적용한 예제: https://refactoring.guru/design-patterns/bridge/swift/example#example-1
- 사용해본 경험이 있는지
- 또 어디에 적용하면 좋을지
- 멀티플랫폼 지원하는 소프트웨어: 다양한 플랫폼을 추상화해서 사용
- 게임: 키보드, 조이스틱, 터치스크린 등으로 조작 가능한 게임 만들 때
참고
https://blog.naver.com/doyoung0205/221761552596
https://book.naver.com/bookdb/book_detail.nhn?bid=4529127
https://joycestudios.tistory.com/38
'스터디' 카테고리의 다른 글
[엘레강트 오브젝트] '생성자에 코드를 넣지 마세요' 적용해보기 (0) | 2021.05.19 |
---|---|
[디자인패턴] Builder 패턴 (1) | 2021.05.18 |
[디자인패턴] Template Method 패턴 (1) | 2021.05.05 |
[디자인패턴] Iterator 패턴을 Swift로 구현해보기 (0) | 2021.05.03 |