References: Do it! 코틀린 프로그래밍
코틀린에서 연관(Association)관계, 의존(Dependency)관계, 집합(Aggregation)관계, 구성(Composition)관계 에 대해 알아봅니다.
1. 클래스간의 관계
클래스간의 관계는 다음과 같이 표시할 수 있습니다.
또한 클래스간의 관계는 다음과 같이 판별할 수 있습니다.
- 연관관계: 클래스간의 참조를 유지하는 경우
- 의존관계: 클래스간의 참조를 유지하지 않는 경우
- 집합관계: 연관관계에 있으면서 객체의 생명주기가 서로 유지되는 경우
- 구성관계: 연관관계에 있으면서 객체의 생명주기가 서로 유지되지 않는 경우
2. 연관(Association)관계
연관관계란 두개의 서로 분리된 클래스가 연결을 갖고 있는것 입니다.
단방향 양방향 연결 모두를 포함하며 서로 다른 생명주기를 가집니다.
다음 예시를 통해 연관 관계에 대해 살펴보겠습니다.
class Doctor(val name: String){
fun patientList(p: Patient){
println("Doctor: $name, Patient: ${p.name}")
}
}
class Patient(val name: String){
fun doctorList(d: Doctor){
println("Patient: $name, Doctor: ${d.name} ")
}
}
fun main() {
val doc = Doctor("DoctorA")
val pat = Patient("PatientA")
doc.patientList(pat)
pat.doctorList(doc)
}
- fun patientList(p: Patient){ / fun doctorList(d: Doctor){: 각 클래스에서 서로 인자를 사용해 참조합니다.
- val doc = Doctor("DoctorA") / val pat = Patient("PatientA"): 객체는 따로 생성함을 보여줍니다.
위의 코드를 실행시키면 다음과 같은 결과를 확인할 수 있습니다.
Doctor와 Patient 클래스는 각각 따로 생성되 독립적인 생명주기를 갖게됩니다. 또한 클래스가 서로 참조하고 있으므로 양방향 참조를 가집니다.
서로 참조는 하고 있지만 객체의 생명주기에 영향을 주지않을 때 연관관계라고 합니다.
3. 의존(Dependency)관계
한 클래스가 다른 클래스에 의존되어 영향을 줄 때 의존관계라 합니다. 예를들어 Doctor 클래스를 생성하려고 할 때 먼저 Patient 클래스가 필요하다면 Doctor는 Patient에 의존하는 관계라고 합니다.
다음 예시를 통해 확인해 봅시다.
class Patient(val name: String, var id: Int){
fun doctorList(d: Doctor){
println("Patient: $name, Doctor: ${d.name} ")
}
}
class Doctor(val name: String, val p: Patient){
val customerId: Int = p.id
fun patientList(){
println("Doctor: $name, Patient: ${p.name}")
println("PatientId: $customerId")
}
}
fun main() {
val pat = Patient("PatientA", 1)
val doc = Doctor("DoctorA", pat)
doc.patientList()
}
- class Doctor(val name: String, val p: Patient): 이전과 달리 Patient 클래스를 주 생성자에서 받고 있습니다.
- val doc = Doctor("DoctorA", pat): Doctor 클래스를 생성하기 위해선 이미 생성된 Patient 클래스가 필요합니다.
위 코드의 실행결과는 다음과 같습니다.
위의 설명과 같이 Doctor 클래스는 Patient 클래스에 의존하게 됩니다.
4. 집합(Aggregation)관계
집합관계는 연관관계와 유사하지만 한 개체가 특정 개체를 소유한 다는 개념이 추가된 것 입니다.
다음 예제를 통해 살펴보겠습니다.
class Pond(_name: String, _members: MutableList<Duck>){
val name: String = _name
val members: MutableList<Duck> = _members
constructor(_name: String): this(_name, mutableListOf<Duck>())
}
class Duck(val name: String){ }
fun main(){
val pond = Pond("myPond")
val duck1 = Duck("Duck1")
val duck2 = Duck("Duck2")
pond.members.add(duck1)
pond.members.add(duck2)
for(duck in pond.members){ println(duck.name) }
}
- _members: MutableList<Duck>: Pond 클래스는 여러 Duck 클래스를 가질 수 있습니다.
- Pond / Duck: 두 클래스는 서로 생명주기에 영향을 미치지 않습니다.
- add: Pond 클래스에 Duck를 추가합니다.
위 코드의 실행결과는 다음과 같습니다
연못에는 여러마리 오리가 존재할 수 있습니다. 한 오리는 한 연못에만 존재할 수 있습니다.
결국 Pond는 객체 Duck를 소유하게 됩니다.
5. 구성(Composition)관계
구성관계는 집합관계와 유사하지만 특정 클래스가 어느 한 클래스의 부분이 되는 것 입니다.
부분이 된 하위 클래스는 생명주기가 상위 클래스에 종속됩니다. 따라서 상위 클래스가 삭제되면 하위 클래스도 같이 삭제 되게 됩니다.
다음 예제를 통해 살펴보겠습니다.
class Engine(power:String){
fun start() = println("Engine has ben started.")
fun stop() = println("Engine has ben stopped.")
}
class Car(val name: String, val power: String){
private var engine = Engine(power)
fun startEngine() = engine.start();
fun stopEngine() = engine.stop();
}
fun main() {
var car = Car("Tico", "100hp")
car.startEngine()
car.stopEngine()
}
- private var engine = Engine(power): 클래스 내부에서 다른 클래스를 생성했습니다.
위의 코드를 실행한 결과는 다음과 같습니다.
위 처럼 프로그래밍을 하면 Engine 클래스는 Car클래스와 함께 생성되며 Car클래스에 생명주기도 종속됩니다. Car 클래스가 삭제되면 Engine 객체도 삭제됩니다.
이 관계를 구성 관계라고 합니다.
'Programming' 카테고리의 다른 글
[Kotlin] 26. 지연초기화: lateinit (0) | 2019.08.27 |
---|---|
[Kotlin] 25. Custom Getter & Setter (0) | 2019.08.27 |
[Kotlin] 23. 다형성(Polymorphism) (0) | 2019.08.24 |
[Kotlin] 22. 상속(Inheritance) (0) | 2019.08.24 |
[Kotlin] 21. 생성자 (0) | 2019.08.24 |