컴포지션은 클래스 안에서 클래스를 사용하는 것을 말합니다.
정확히 말하면 클래스 안에서 다른 클래스를 객체로 생성하여 사용하는 개념입니다.
가령 아래와 같은 클래스가 있다고 가정해봅시다.
class Engine(power:String) {
fun start() = println("Engine had been started")
fun stop() = println("Engine has been stopped")
}
멤버변수 power
와 멤버 메서드 start
와 stop
을 갖습니다.
이렇게 만들어진 클래스를 객체로 생성하여 다른 클래스에서 사용해보겠습니다.
class Car(val name:String, val power:String) {
private var engine = Engine(power)
fun startEngine() = engine.start()
fun stopEngine() = engine.stop()
}
Car
라는 클래스 안에서 Engine
이라는 클래스로 객체를 생성해주었고 여기에서는 name
이라는 멤버변수가 생성자에 포함되어 있습니다.
여기에서 원래 Engine
클래스의 멤버변수로 power
라는 변수가 있었기 때문에 Engine
객체의 변수로 받아주기 위해 Car
의 생성자에 Engine
객체의 멤버변수를 넣어주었습니다.
클래스 내부에서 클래스를 생성하였기 때문에 멤버 메서드를 호출해서 사용할 수 있습니다.
이 때는 상속 개념이 아니기 때문에 오버라이드라고 말할 수 없습니다.
제네릭은 타입을 파라미터로 가지는 클래스와 인터페이스를 의미합니다.
이전에 자료형 변수로 정의하였으며 각 타입 파라미터는 다음과 같았습니다.
E - Element
K - Key
N - Number
T - Type
V - Value
R - ReturnType
클래스를 선언할 때 제네릭을 사용할 수 있습니다.
예를 들어
class Box<T>(var value:T)
이라는 클래스를 선언한다면 이 클래스를 객체로 생성할 때 T
라는 자리에 알맞은 자료형을 넣어주면 됩니다.
이 클래스를 메인함수에서 객체로 만들어 사용한다면
fun main(args: Array<String>) {
val box:Box<Int> = Box<Int>(123)
println(box.value)
}
이렇게 Int
타입으로 선언하여 value
로 123을 넣어 콘솔에 출력하도록 했습니다.
이처럼 <T>
는 불특정 자료형임을 알려주고, 객체로 생성하여 사용할 때 자료형을 밝혀주어 사용할 수 있습니다.
함수도 마찬가지 입니다.
fun<T> add(x:T, y:T, op:(T, T) -> T) : T = op(x, y)
다음과 같은 함수가 있다고 가정할 때,
T
는 어떤 자료형이 올 지 사용되기 전까지는 지정되지 않은 형태입니다.
이 함수는 자료형 T
를 갖는 두 개의 매개변수를 받아 이를 처리하여 하나의 자료형으로 return 해주는 형태입니다.
이 때 매개변수의 op
는 두개의 자료형에 대해 하나의 자료형으로 처리해주는 메서드입니다.
리턴해줄 값은 op(x, y)
의 연산결과입니다.
fun main(args: Array<String>) {
val res = add(3, 4) {x, y -> x + y}
println(res)
}
위와 같이 메인함수에서 사용할 수 있습니다. 각각의 매개변수를 받고 op
메서드는 두 값에 대해 덧셈 연산을 해줍니다.
제네릭을 한개만 사용할 수 있는 것은 아닙니다.
class MyClass<T1, T2>(n1:T1, n2:T2) {
var num1 = n1
var num2 = n2
/*
fun myFunction() {
return num1 + num2 // 자료형이 명확하지 않으므로 연산할 수 없음
}
*/
}
주의해야 할 사항으로 제네릭을 갖는 클래스에서는 연산 결과를 리턴하는 멤버 메서드를 생성할 수 없습니다.
자료형이 명확하지 않기 때문에 연산할 수 없는 것입니다.
메인함수에서 다음과 같이 사용하였습니다.
fun main(args: Array<String>) {
val cal:MyClass<Int, Double> = MyClass<Int, Double>(43, 4995.12)
println(cal.num1)
println(cal.num2)
}