본문 바로가기
Kotlin

Kotlin #7 : 정보 은닉 캡슐화 (연관, 의존, 집합, 구성) 230220

by haheehee 2023. 2. 20.

++ 캡슐화(encapsulation) ++

- 클래스를 작성할 때 외부에서 숨겨야 하는 속성이나 기능

- 가시성 지시자(visibility modifiers)를 통해 외부 접근 범위를 결정할 수 있음

  • private: 이 지시자가 붙은 요소는 외부에서 접근할 수 없음
  • public: 이 요소는 어디서든 접근이 가능 (기본값)
  • protected: 외부에서 접근할 수 없으나 하위 상속 요소에서는 가능
  • internal: 같은 정의의 모듈 내부에서는 접근이 가능
접근 제한자 최상위에서 사용할 때  클래스 멤버에서 사용할 때
public 모든 파일에서 가능 모든 클래스에서 가능
internal 같은 모듈 내에서 가능 같은 모듈 내에서 가능
protected 사용 불가 상속 관계의 하위 클래스에서만 가능
private 파일 내부에서만 사용 클래스 내부에서만

package com.example.pp151

private class PrivateClass {
    private var i = 1
    private fun privateFunc() {
        i += 1  // 접근 허용
    }
    fun access() {
        privateFunc()   // 접근 허용
    }
}

class OtherClass {
   // val opc = PrivateClass()    // 불가능 - 프로퍼티인 opc는 private이 되어야 한다.
    fun test() {
        val pc = PrivateClass() // 생성 가능
    }
}

fun main() {
    val pc = PrivateClass() // 생성 가능
   // pc.i    // 접근 불가
   // pc.privateFunc()    // 접근 불가
}

fun TopFunction() {
    val tpc = PrivateClass()    // 객체 생성 가능
}

private 가시성 테스트 예제

 

package com.example.pp152

open class Base {   // 최상위 선언 클래스에는 protected를 사용할 수 없다.
    protected var i = 1
    protected fun protectedFunc() {
        i += 1  // 접근 허용
    }
    fun access() {
        protectedFunc() // 접근 허용
    }
    protected class Nested  // 내부 클래스에는 지시자 허용
}

class Derived : Base() {
    fun test(base: Base): Int {
        protectedFunc() // Base 클래스의 메서드 접근 가능
        return i    // Base 클래스의 프로퍼티 접근 가능
    }
}

fun main() {
    val base = Base()   // 생성 가능
    base.i  // 접근 불가
    base.protectedFunc()    // 접근 불가
    base.access()   // 접근 가능
}

protected 가시성 테스트 예제

 

package com.example.pp154

internal class InternalClass {
    internal var i = 1
    internal fun icFunc() {
        i += 1  // 접근 허용
        println(i)
    }
    fun access() {
        icFunc() // 접근 허용
    }
}

class Other {
    internal val ic = InternalClass() // 프로퍼티 지정 시 internal로 맞춰야 한다.
    fun test() {
        println(ic.i)   // 접근 허용
        println(ic.icFunc())    // 접근 허용
    }
}

fun main() {
    val mic = InternalClass()   // 생성 가능
    mic.i   // 접근 허용
    mic.icFunc()    // 접근 허용
    val other = Other()
    other.test()
}

internal 가시성 테스트 예제

 


UML

- : public

# : private + 상속 (같은 클래스 내에서 사용 가능), 상속하는 Derived에서 가능

~ : default, internal과 거의 같다. 

+ : public

package com.example.pp156

open class Base {
    // 이 클래스에서는 a, b, c, d, e 접근 가능
    private val a = 1
    protected open val b = 2
    internal val c = 3
    val d = 4   // 가시성 지시자 기본값은 public
    protected class Nested {
        // 이 클래스에서는 a, b, c, d, e, f 접근 가능
        public val e: Int = 5   // public 생략 가능
        private val f: Int = 6
    }
}

class Derived: Base() {
    // 이 클래스에서는 b, c, d, e 접근 가능 - a는 접근 불가
    override val b = 5  // Base의 'b'는 오버라이딩됨. - 상위와 같은 protected 지시자
}

class Other(base: Base) {
    // base.a, base.b는 접근 불가
    // base.c와 base.d는 접근 가능(같은 모듈 안에 있으므로)
    // Base.Nested는 접근 불가, Nested::e 역시 접근 불가
}

가시성 지시자와 클래스의 관계

 

 


++ 관계(relationship) ++

- 연관(association)

- 의존(dependency)

- 집합(aggregation)          "has a"

- 구성(composition)          "owns a"


package com.example.pp160

class Patient(val name: String) {
    fun doctorList(d: Doctor) {     // 인자로 참조
        println("Patient: $name, Doctor: ${d.name}")
    }
}

class Doctor(val name: String) {
    fun patientList(p: Patient) {   // 인자로 참조
        println("Doctor: $name, Patient: ${p.name}")
    }
}

fun main() {
    val doc1 = Doctor("Kimsabu") // 객체가 따로 생성된다.
    val patient1 = Patient("Kildong")
    doc1.patientList(patient1)
    patient1.doctorList(doc1)
}

 

연관 관계 나타내기 예제

Association

 

package com.example.pp161

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("Patient Id: $customerId")
    }
}

fun main() {
    val patient1 = Patient("Kildong", 1234)
    val doc1 = Doctor("Kimsabu", patient1)
    doc1.patientList()
}

의존 관계 나타내기 예제

Dependency

 

package com.example.pp162

// 여러 마리의 오리를 위한 List 매개 변수
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("myFavorite")
    val duck1 = Duck("Duck1")
    val duck2 = Duck("Duck2")
    // 연못에 오리를 추가 - 연못에 오리가 집합한다.
    pond.members.add(duck1)
    pond.members.add(duck2)
    // 연못에 있는 오리들
    for(duck in pond.members) {
        println(duck.name)
    }
}

집합 관계 나타내기 예제

Aggregation

 

package com.example.pp163

class Car(val name: String, val power: String) {
    private var engine = Engine(power) // Engine 클래스 객체는 Car에 의존적

    fun startEngine() = engine.start()
    fun stopEngine() = engine.stop()
}

class Engine(power: String) {
    fun start() = println("Engine has been started.")
    fun stop() = println("Engine has been stopped.")
}

fun main() {
    val car = Car("tico", "100hp")
    car.startEngine()
    car.stopEngine()
}

구성 관계 나타내기 예제

Composition

 

 

 

 

 

 

 

 

댓글