플라이웨이트 패턴이란 다수의 인스턴스를 생성할 때에 메모리를 절약하기 위한 구조 패턴 중의 하나이다.
모든 객체의 데이터를 유지하는 대신에, 이미 존재하는 객체는 더이상 생성하지 않고 기존에 있는 객체를 return한다.
이렇게 공유되는 자원을 flyweight라 하고, 이를 참조하는 여러 객체들을 client라고 한다.
아래에서 살펴볼 Log를 찍는 Logger를 예로 들면, 모든 Logger가 몇 가지 정해진 Printer를 공유한다. Logger를 생성할 때마다 새로운 Printer를 만들 필요가 없기 때문에 메모리를 더 효율적으로 사용할 수 있다.
플라이웨이트 패턴을 사용하기 위해서 가장 핵심적인 부분은 이미 만들어진 flyweight들을 관리할 로직이 존재해야 한다는 것이다. static 메서드 또는 프로퍼티를 사용하여 이미 존재하는 인스턴스인지 판별하고 적절한 인스턴스를 return하거나 새로 만들어 줄 수 있다.
샘플코드
Logging : Logger Class가 채택할 프로토콜 및 열거형
public protocol Logging {
var subsystem: String {get}
var category: String {get}
init(subsystem: String, category: String, printer: PrinterType)
func log(_ message: String,
type: LogType,
file: String,
function: String,
line: Int)
}
public enum LogType {
case info
case warning
case error
}
extension LogType: CustomStringConvertible {
public var description: String {
switch(self) {
case .info:
return "INFO"
case .warning:
return "WARNING"
case .error:
return "ERROR"
}
}
}
Logger Class : printer protocol에 의존하여 log 기능을 사용할 수 있다.
public class Logger: Logging {
public let subsystem: String
public let category: String
let printer: Printer
required public init(subsystem: String, category: String, printer: PrinterType) {
self.printer = PrinterFactory.printer(for: subsystem, category: category, type: printer)
self.subsystem = subsystem
self.category = category
}
public func log(_ message: String,
type: LogType,
file: String = #file,
function: String = #function,
line: Int = #line) {
printer.output(message, type: type, file: file, function: function, line: line)
}
}
Logger 클래스는 Logging 프로토콜을 채택하여 구현한다. 또한 PrinterType, SubSytem, Category를 인자로 받는 PrinterFactory에서 생산된 printer에 의존하여 printer.output을 통해 Log를 출력하는 것을 볼 수 있다.
PrinterType에는 ConsolePrinter와 FilePrinter가 있는데, 이들은 Printer 프로토콜을 채택하였기 때문에 output의 기능을 가진다.
PrinterFactory : Dictionary 타입을 통해 static하게 고유 키를 가진 프린터들을 저장하고 있다.
struct PrinterFactory {
private static var printersByID = Dictionary<String, Printer>()
static func printer(for subsystem: String, category: String, type: PrinterType) -> Printer {
let result: Printer
let key = subsystem+category+type.rawValue
if let printer = printersByID[key] {
result = printer
} else {
switch type {
case .console:
result = ConsolePrinter()
case .file:
result = FilePrinter()
}
printersByID[key] = result
}
return result
}
}
Dictionary와 static variable을 통해서 이미 생성된 Printer들의 key를 저장하고 있다.
if let 구문에서 딕셔너리에 동일한 key를 가진 printer가 이미 존재하는 경우에는 printer()의 결과로 기존에 만들어져 있던 printer를 반환한다.
key를 가진 printer가 존재하지 않는 경우 새로운 printer를 만들어서 반환해준다.
Flyweight Pattern이란?
플라이웨이트 패턴이란 다수의 인스턴스를 생성할 때에 메모리를 절약하기 위한 구조 패턴 중의 하나이다. 모든 객체의 데이터를 유지하는 대신에, 이미 존재하는 객체는 더이상 생성하지 않고 기존에 있는 객체를 return한다.
이렇게 공유되는 자원을 flyweight라 하고, 이를 참조하는 여러 객체들을 client라고 한다. 아래에서 살펴볼 Log를 찍는 Logger를 예로 들면, 모든 Logger가 몇 가지 정해진 Printer를 공유한다. Logger를 생성할 때마다 새로운 Printer를 만들 필요가 없기 때문에 메모리를 더 효율적으로 사용할 수 있다.
플라이웨이트 패턴을 사용하기 위해서 가장 핵심적인 부분은 이미 만들어진 flyweight들을 관리할 로직이 존재해야 한다는 것이다. static 메서드 또는 프로퍼티를 사용하여 이미 존재하는 인스턴스인지 판별하고 적절한 인스턴스를 return하거나 새로 만들어 줄 수 있다.
샘플코드
Logging : Logger Class가 채택할 프로토콜 및 열거형
Logger Class : printer protocol에 의존하여
log
기능을 사용할 수 있다.Logger 클래스는 Logging 프로토콜을 채택하여 구현한다. 또한 PrinterType, SubSytem, Category를 인자로 받는 PrinterFactory에서 생산된 printer에 의존하여
printer.output
을 통해 Log를 출력하는 것을 볼 수 있다.Printer 프로토콜과 이를 채택한 구체 Printer들
PrinterType에는 ConsolePrinter와 FilePrinter가 있는데, 이들은 Printer 프로토콜을 채택하였기 때문에 output의 기능을 가진다.
PrinterFactory : Dictionary 타입을 통해 static하게 고유 키를 가진 프린터들을 저장하고 있다.
Dictionary와 static variable을 통해서 이미 생성된 Printer들의 key를 저장하고 있다.
if let
구문에서 딕셔너리에 동일한 key를 가진 printer가 이미 존재하는 경우에는printer()
의 결과로 기존에 만들어져 있던 printer를 반환한다.