생성패턴 - 프로토타입
이전 글 : 생성패턴 - 빌더
2023.05.25 - [Engineering/SW Design] - [디자인 패턴] 생성패턴 - 빌더
요약
코드를 그들의 클래스에 의존시키지 않고, 기존 객체들을 복사할 수 있도록 해주는 패턴이다.
객체를 생성할때 완전 새로 new 생성자를 활용해서 인스턴스를 만들기 보다는, 이미 만들어진 인스턴스의 내용 일부를 수정하여 사용하고 싶을때가 있다.
그런 경우, clone() 메서드를 활용하여 인스턴스를 생성할 수 있는데, 이런 개념을 확장하여 아예 처음부터 일반적인 프로토타입을 만들어 두고, 그것을 복사해서 필요한 부분을 수정해서 사용하는 것이다.
이러한 패턴을 따르면 new object()로 객체를 생성하는 것보다 더 펀리하게 쓸 수 있다.
키워드 : clone() / 이미 생성 된 인스턴스를 복제
문제
객체가 있고 그 객체의 정확한 복사본을 만드는 상황을 가정 하자면,
- 먼저 같은 클래스의 새 객체를 new를 통해 생성해야 하고.
- 그런 다음 원본 객체의 모든 필드들을 살펴본 후 해당 값들을 새 객체에 복사해야 한다.
하지만, 객체의 필드들 중 일부가 비공개라면, 객체 자체의 외부에서 볼 수 없을 수 있으므로 모든 객체를 그런 식으로 복사하지 못한다.
또한 객체의 복제본을 생성하려면 객체의 클래스를 알아야 하므로, 코드가 해당 클래스에 의존하게 된다는 는 단점 또한 존재 한다.
여기에 객체 생성시마다 DB 커넥션을 맺는 기능을 포함한다면, 인스턴스를 생성할 때마다 큰 자원의 소모를 요구할 것이다.
해결책
프로토타입 패턴은 실제로 복제되는 객체들에 복제 프로세스를 위임하며, 복제의 결과물이 될 모든 객체에 대한 공통 인터페이스를 선언한다.
인터페이스를 사용하면 코드를 객체의 클래스에 결합하지 않고도 해당 객체를 복제할 수 있으며, 일반적으로 이러한 인터페이스에는 단일 clone 메서드만 포함된다.
clone 메서드는 현재 클래스의 객체를 만든 후 이전 객체의 모든 필드 값을 새 객체로 전달한다.
이때 객체들이 같은 클래스에 속한 다른 객체의 비공개 필드들에 접근(access) 할 수 있도록 하므로 비공개 필드들을 복사하는 것도 가능하다.
복제를 해줄 수 있게 하는 객체를 프로토타입이라고 하며, 사용하는 방법은 간단하다.
일반적으로 아래와 같은 스텝으로 프로토타입 패턴은 달성 된다.
- 다양한 방식으로 설정된 객체들의 집합을 만든다.
- 그 후 설정한 것과 비슷한 객체가 필요할 경우 처음부터 새 객체를 생성하는 대신 프로토타입을 복제한다.
구조
Hands on
- 자전거 클래스의 객체 생성을 예로 들어본다.
<<Bike.kt>>
open class Bike : Cloneable {
private var gears: Int = 0
private var bikeType: String? = null
var model: String? = null
private set
init {
bikeType = "Standard"
model = "general"
gears = 4
}
public override fun clone(): Bike {
return Bike()
}
fun makeAdvanced(){
bikeType = "Advanced"
model = "super"
gears = 12
}
}
- BIke 클래스는 clone() 을 제공하는 프로토타입 클래스이다.
- private init 메서드로서 객체 생성시 내부적으로 Standard 타입의 Bike 를 리턴한다.
- 여기에 makeAdvanced() 을 제공하여 Advanced 타입의 Bike 를 세팅 해주기도 한다.
<<클라이언트 코드>>
fun makeSuper(basicBike: Bike): Bike {
basicBike.makeAdvanced()
return basicBike
}
fun main(args: Array<String>) {
val bike = Bike()
val basicBike = bike.clone()
val advancedBike = makeSuper(basicBike)
println("프로토타입을 통해 생성된 슈퍼 바이크" + advancedBike.model)
}
- 클라이언트 코드에서 Bike() 클래스를 기본 인스턴스로 일단 만들어 두고,
- makeSuper() 클래스에서 프로토타입 인터페이스 내의 makeAdvanced() 를 호출하여 슈퍼 자전거로 값을 세팅하였다.
핵심
- 객체를 생성하는데 비용이들거나, 이미 유사한 객체가 존재하는 경우에 사용된다.
- 프로토타입 패턴은 각자의 객체를 초기화하는 방식만 다른 자식 클래스들의 수를 줄이고 싶을 때 사용된다.
- clone할 때 얕은 복사와 깊은 복사 둘 다 이루어진다.
- primitive한 타입들은 깊은 복사가 이루어지지만(값이 넘어가므로), heap에 올라가는 객체들은 얕은 복사가 이루어진다.
- 즉, 생성 비용이 큰 경우 새로 생성하는 대신 다른 객체를 복사하는 패턴
프로토타입은 인스턴스 객체 상태에서의 Clone 이 핵심이다.
'Engineering > SW Design' 카테고리의 다른 글
[디자인 패턴] 구조패턴 - 어댑터 (0) | 2024.03.25 |
---|---|
[디자인 패턴] 생성패턴 - 싱글턴 (0) | 2024.03.11 |
[디자인 패턴] 생성패턴 - 빌더 (0) | 2023.05.25 |
[디자인 패턴] 생성패턴 - 추상 팩토리 (1) | 2023.05.24 |
[디자인 패턴] 생성패턴 - 팩토리 메서드 (0) | 2023.05.22 |
댓글