인터페이스와 추상 클래스는 객체 지향 프로그래밍에서 코드 재사용과 다형성을 구현하는 데 사용되는 개념이다. 둘을 비슷한 개념으로 볼 수 있지만, 인터페이스에서는 프로퍼티의 상태 정보를 저장할 수 없다.
interface Car {
var kind : String // 추상 프로퍼티
fun code() // 추상 메소드
fun drive() { // 구현부를 포함할 수 있다. 구현부를 포함하면 일반 메소드
println("go to my home")
}
}
interface
키워드를 사용하여 선언한다.override
키워드를 앞에 넣어야한다.val
로 선언한 프로퍼티는 게터를 통해서 필요한 내용 구현 가능.interface Car {
var name : String // 추상 프로퍼티
val maxSpeed: Double // val로 선언하면 게터 구현 가능
get() = 130.0
fun navi() // 추상 메소드
fun drive() { // 구현부를 포함할 수 있다. 구현부를 포함하면 일반 메소드
println("go to my home")
}
}
class Electronic(override var name : String) : Car { // 주생성자를 이용
init {
println("이름은 ${name}입니다.")
}
override fun navi() {
println("navi 메소드가 구현되었습니다.")
}
}
interface Ad {
var melee: Double // val로 선언하면 게터 구현 가능
fun offense_power() // 추상 메소드
fun attack() { // 구현부를 포함할 수 있다. 구현부를 포함하면 일반 메소드
println("으쌰")
}
}
interface Ap {
var ld: Double // val로 선언하면 게터 구현 가능
fun spell_power() // 추상 메소드
fun attack() { // 구현부를 포함할 수 있다. 구현부를 포함하면 일반 메소드
println("아브라카다브라")
}
}
class Item: Ad, Ap { // 주생성자를 이용
override var melee: Double = 1.0
override var ld: Double = 40.0
override fun offense_power() {
println("offense_power 메소드")
}
override fun spell_power() {
println("sppel_power 메소드")
}
override fun attack() {
super<Ad>.attack()
}
}
구현부가 있는 메소드의 경우 필요에 따라 오버라이딩을 하면 된다. 이때 인터페이스에서 구현한 메소드의 이름이 같은 경우에 super<인터페이스 이름>.메소드 명
형식으로 구분 가능하다.
추상메소드를 가지고 있는 클래스.
abstract
키워드 사용해야함.abstract
로 선언할 수 있다. -> 상속받는 클래스에서 구체화한다는 의미open
키워드 사용하지 않음.// abstract로 정의한 추상 클래스이다. 주생성자를 사용했다.
abstract class Cat(val name : String, val color : String, val weight : Double) {
// abstract로 정의한 추상 프로퍼티이므로 하위 클래스에서 반드시 재정의해야한다.
abstract var sleep : Double
// 초기값을 갖는 일반 프로퍼티 (인터페이스에서는 불가능)
var birth = 2015
// abstract로 정의한 추상 메소드이므로 하위 클래스에서 반드시 재정의해야한다.
abstract fun cry()
abstract fun eat()
fun intro() {
println("Name : $name, Color : $color, Weight : $weight, Sleep : $sleep, MaxSpeed : $birth")
}
}
class RussianBlue(name : String, color : String, weight : Double, override var sleep : Double) : Cat(name, color, weight) {
override fun cry() {
// 재정의
println("RussianBlue cry")
}
override fun eat() {
// 재정의
println("RussianBlue eat")
}
}
class Siamese(name : String, color : String, weight : Double, override var sleep : Double) : Cat(name, color, weight) {
override fun cry() {
// 재정의
println("Siamese cry")
}
override fun eat() {
// 재정의
println("Siamese eat")
}
}
fun main() {
// 추상 클래스
val rb = RussianBlue("yom", "gray", 2.7, 13.37)
val s = Siamese("mez", "beige", 3.5, 12.13)
s.birth = 2019
rb.eat()
rb.intro()
s.cry()
s.intro()
}
RussianBlue eat
Name : yom, Color : gray, Weight : 2.7, Sleep : 13.37, MaxSpeed : 2015
Siamese cry
Name : mez, Color : beige, Weight : 3.5, Sleep : 12.13, MaxSpeed : 2019
코드를 보면 s.birth
프로퍼티의 초기값을 변경한 것을 각각 intro()
메소드를 출력하여 확인할 수 있다.
결론적으로, 프로퍼티나 메소드에 abstract
키워드를 사용한 것은 하위 클래스에서 override
해야한다.
Reference