플라이웨이트 패턴
- 공유를 통해 많은 수의 fine-grained(쪼개진 것) 객체들을 효과적으로 지원.
- 이 패턴에서 중요한 개념은 본질적인(intrincsic), 부가적인(extrinsic) 상태
- 본질적인 상태: 객체의 상수 데이터, 공유되는 상태
- 부가적인 상태: 다른 객체들에 의해 '외부에서' 변경되는 객체의 나머지 상태, 가변적인 상태
- 플라이웨이트 패턴의 유일한 목적은 메모리 사용을 최소화
- RAM 부족으로 문제를 겪지 않는다면 이 패턴을 무시할 수 있다.
활용성
- 대량의 객체를 사용해야 할 때
- 객체의 수가 너무 많아져 저장 비용이 너무 높아질 때
- 대부분의 객체 상태를 부가적인 것으로 만들 수 있을 때
구조
요소
- Flyweight
- Flyweight가 받아들일 수 있고, 부가적 상태에서 동작해야 하는 인터페이스 선언
- ConcreteFlyweight
- Flyweight 인터페이스 구현하고 내부적으로 갖고 있어야 하는 본질적 상태에 대한 저장소
- UnshaerdConcreteFlyweight
- 모든 플라이급 객체들이 공유될 필요는 없기 때문에 따로 분리할 수 있다. (필수요소는 아닌듯)
- FlyweightFactory
- 플라이급 객체를 생성하고 관리하며, 플라이급 객체가 제대로 공유되도록 보장한다.
- 사용자가 플라이급 객체를 요청하면, 팩토리는 인스턴스를 제공.
- Client
- 플라이급 객체에 대한 참조자를 관리
- 플라이급 객체의 부가적 상태를 저장
협력 방법
- 플라이급 객체가 기능을 수행하는 데 필요한 상태가 본질적인 것인지 부가적인 것인지 구분
- 본질적 상태는 ConcreteFlyweight에 저장
- 부가적인 상태는 사용자가 저장하거나, 연산되어야 하는 다른 상태로 관리
- 사용자는 연산을 호출할 때 자신에게만 필요한 부가적 상태를 플라이급 객체에 매개변수로 전달.
- 사용자는 ConcreteFlyweight 객체를 FlyweightFactory 객체에서 얻어야 함.
- 그래야 플라이급 객체가 공유될 수 있다.
장점
- 공유해야 하는 인스턴스의 전체 수를 줄일 수 있다.
- 객체별 본질적 상태의 양을 줄일 수 있다.
- 부가적인 상태는 연산되거나 저장될 수 있다.
단점
- 플라이웨이트 메서드를 호출할 때마다 데이터의 일부를 다시 계산해야 한다면 CPU가 낭비될 수 있다.
- 코드가 복잡해짐.
예시 코드
protocol GrootFlyweight {
func iAmGroot(_ numberOfYellowBirds: Int)
}
class GrootConcreteFlyweight: GrootFlyweight {
private let hairColor: HairColor
init(hairColor: HairColor) {
self.hairColor = hairColor
}
func iAmGroot(_ numberOfYellowBirds: Int) {
print("I Am \(numberOfYellowBirds) birds \(hairColor) Groot!")
}
}
enum HairColor: String {
case red
case blue
case yellow
case green
}
class GrootFlyweightFactory {
private var grootPool: [HairColor: GrootFlyweight] = [:]
func groot(hairColor: HairColor) -> GrootConcreteFlyweight {
let key = hairColor
if let existingGroot = grootPool[key] {
return existingGroot as! GrootConcreteFlyweight
} else {
let newGroot: GrootFlyweight = GrootConcreteFlyweight(
hairColor: hairColor
)
grootPool[key] = newGroot
return newGroot as! GrootConcreteFlyweight
}
}
func element() {
print(grootPool)
}
}
let grootFactory = GrootFlyweightFactory()
var groot1 = grootFactory.groot(hairColor: .green)
var groot2 = grootFactory.groot(hairColor: .blue)
var groot3 = grootFactory.groot(hairColor: .yellow)
var groot4 = grootFactory.groot(hairColor: .green)
groot1.iAmGroot(3)
groot2.iAmGroot(5)
groot3.iAmGroot(6)
groot4.iAmGroot(5)
grootFactory.element()
참고