상속은 이미 존재하는 클래스의 기능을 확장하거나 수정하는 것에 초점을 맞춘다. 코드의 재사용성과 유지보수의 용이성을 제공한다.
추상화는 복잡한 시스템을 간단하게 표현하는 것에 초첨을 맞춘다.
클래스 | 추상클래스 |
---|---|
설계도 | 미완성된 설계도 |
추상 메서드가 1개 이상 존재 | |
인스턴스 생성 | 상속을 통해 추상 메서드를 완성(구현)해야 인스턴스 생성 가능 |
꼭 필요한 메서드를 자손마다 다르게 구현될 것으로 예상되는 경우 사용 |
부모클래스로 여러가지 메뉴 객체 만들기
fun main(args: Array<String>) {
val burgers = Menu("Burgers", "앵거스 비프 버거")
val frozenCustard = Menu("Frozen Custard", "매장에서 신선하게 만드는 아이스크림")
burgers.displayInfo() // 이름 : Burgers, 설명: [ 앵거스 비프 버거 ]
frozenCustard.displayInfo() // 이름 : Frozen Custard, 설명: [ 매장에서 신선하게 만드는 아이스크림 ]
}
open class Menu(
private val name: String,
private val description: String,
) {
open fun displayInfo() {
println("이름 : $name, 설명: [ $description ]")
}
}
+ 가변 리스트에 담아 for문으로 메뉴 나오게 하기
fun main(args: Array<String>) {
val burgers = Menu("Burgers", "앵거스 비프 버거")
val frozenCustard = Menu("Frozen Custard", "매장에서 신선하게 만드는 아이스크림")
val menus = mutableListOf<Menu>()
menus.add(burgers)
menus.add(frozenCustard)
for (menu in menus) {
menu.displayInfo()
// 이름 : Burgers, 설명: [ 앵거스 비프 버거 ]
// 이름 : Frozen Custard, 설명: [ 매장에서 신선하게 만드는 아이스크림 ]
}
}
open class Menu(
private val name: String,
private val description: String,
) {
open fun displayInfo() {
println("이름 : $name, 설명: [ $description ]")
}
}
+ 데이터니까 불가면 리스트에 담기
Menu를 상속받은 burgers, frozenCustard 객체 생성
fun main(args: Array<String>) {
val burgers = Menu("Burgers", "앵거스 비프 버거")
val frozenCustard = Menu("Frozen Custard", "매장에서 신선하게 만드는 아이스크림")
val menus = listOf<Menu>(burgers, frozenCustard)
for (menu in menus) {
menu.displayInfo()
}
}
open class Menu(
private val name: String,
private val description: String,
) {
open fun displayInfo() {
println("이름 : $name, 설명: [ $description ]")
}
}
+ Menu 클래스를 상속받은 Food 클래스 - displayInfo() 오버라이딩 -> 음식 가격 추가
fun main(args: Array<String>) {
val menus = listOf( // 빈 리스트를 선언 할 경우에만 val menus = listOf<Menu>() => <> 자리에 타입 명시
Menu("burgers", "앵거스 비프 버거"),
Menu("Frozen Custard", "매장에서 신선하게 만드는 아이스크림")
)
for (menu in menus) {
menu.displayInfo()
// 이름 : burgers, 설명: [ 앵거스 비프 버거 ]
// 이름 : Frozen Custard, 설명: [ 매장에서 신선하게 만드는 아이스크림 ]
}
1)
val food1 = Food("ShackBurger", "토마토, 양상추, 쉑소스가 토핑된 치즈버거", 6.9)
val food2 = Food("SmokeShack","베이컨, 체리 페퍼에 쉑소스가 토핑된 치즈버거", 8.9)
val foods = listOf(food1, food2)
2)
val foods = listOf(
Food("ShackBurger", "토마토, 양상추, 쉑소스가 토핑된 치즈버거", 6.9),
Food("SmokeShack","베이컨, 체리 페퍼에 쉑소스가 토핑된 치즈버거", 8.9)
)
1.2 공통 for문)
for (food in foods) {
food.displayInfo()
// 이름: ShackBurger, 설명: [ 토마토, 양상추, 쉑소스가 토핑된 치즈버거 ], 가격: 6.9
// 이름: SmokeShack, 설명: [ 베이컨, 체리 페퍼에 쉑소스가 토핑된 치즈버거 ], 가격: 8.9
}
}
open class Menu(
private val name: String,
private val description: String,
) {
open fun displayInfo() {
println("이름 : $name, 설명: [ $description ]")
}
}
open class Food(
private val name: String,
private val description: String,
private val price: Double,
): Menu(name, description) {
override fun displayInfo() {
println("이름: $name, 설명: [ $description ], 가격: $price")
}
}
+ Food 클래스 객체를 매개변수로 받은 Order 클래스, food 매개변수로 Food 클래스의 displayInfo() 접근
fun main(args: Array<String>) {
println("-------------------------------------Food Menu-------------------------------------------------")
val menus = listOf( // 빈 리스트를 선언 할 경우에만 val menus = listOf<Menu>() => <> 자리에 타입 명시
Menu("burgers", "앵거스 비프 버거"),
Menu("Frozen Custard", "매장에서 신선하게 만드는 아이스크림")
)
for (menu in menus) {
menu.displayInfo()
}
println("-------------------------------------Food Menu-------------------------------------------------")
val foods = listOf(
Food("ShackBurger", "토마토, 양상추, 쉑소스가 토핑된 치즈버거", 6.9),
Food("SmokeShack","베이컨, 체리 페퍼에 쉑소스가 토핑된 치즈버거", 8.9)
)
for (food in foods) {
food.displayInfo()
}
println("--------------------------------------장바구니 목록-----------------------------------------------")
val orders: MutableList<Order> = mutableListOf() // val orders = mutableListOf<Order>() 와 같음
orders.add(Order(foods[0]))
orders.add(Order(foods[1]))
for (order in orders) {
order.food.displayInfo()
}
}
class Order(val food: Food) {
}
open class Menu(
private val name: String,
private val description: String,
) {
open fun displayInfo() {
println("이름 : $name, 설명: [ $description ]")
}
}
open class Food(
private val name: String,
private val description: String,
private val price: Double,
) : Menu(name, description) {
override fun displayInfo() {
println("이름: $name, 설명: [ $description ], 가격: $price")
}
}
abstract class Shape {
abstract val name: String
abstract fun area(): Double
}
class Rectangle(width: Double, height: Double) : Shape() {
override val name: String = "Rectangle"
private val w: Double = width
private val h: Double = height
override fun area(): Double = w * h
}
class Circle(radius: Double) : Shape() {
override val name: String = "Circle"
private val r: Double = radius
override fun area(): Double = 3.14 * r * r
}
두 대상(객체) 간의 '연결, 대화, 소통'을 돕는 '중간 역할'을 한다.
추상 메서드의 집합.
구현된 것이 전혀 없는 설계도. 껍데기(모든 멤버가 public)
interface Vehicle {
fun getNumberOfWheels(): Int
companion object {
const val DOUBLE_TRACK_AMOUNT_OF_WHEELS = 3
fun isDoubleTrack(vehicle: Vehicle) = vehicle.getNumberOfWheels() > DOUBLE_TRACK_AMOUNT_OF_WHEELS
}
}
동행객체는 공통 상수를 제공한다. 이 상수들은 더블트랙 자동차의 최소 바퀴수를 의미한다. 동행객체 안에 또 헬퍼 메서드 isDoubleTrack()도 있다. 인터페이스 내 공통 상수들과 헬퍼 메소드는 동행객체와 함께 일반적으로 사용된다. 동행객체는 인터페이스 구현에 일절 영향을 주지 않는다.
Helper method : 반복적으로 호출이 필요한 경우 매번 새로 정의하지 않고 한 번 선언이 돼 불필요하게 반복되는 코드를 줄여주는 목적으로 사용된다.
interface Vehicle {
fun getNumberOfWheels(): Int // 메서드에 할당한 숫자를 리턴. 변수처럼 사용.
companion object {
const val DOUBLE_TRACK_AMOUNT_OF_WHEELS = 3
fun isDoubleTrack(vehicle: Vehicle) = vehicle.getNumberOfWheels() > DOUBLE_TRACK_AMOUNT_OF_WHEELS
}
}
class Car(val brand: String, val model: String, val age: Int) : Vehicle {
companion object {
const val ANTIQUE_CAR_MINIMAL_AGE = 30
}
override fun getNumberOfWheels() = 4
fun isAntique() = age >= ANTIQUE_CAR_MINIMAL_AGE
}
class VehicleImplementedInCompanionObject { // 클래스 내 동행객체로 자전거 바퀴 수 싱글톤 생성
companion object Bicycle : Vehicle {
override fun getNumberOfWheels(): Int {
return 2
}
}
}
fun main(args: Array<String>) {
fun implementing_Vehicle(){
val car = Car("Ford", "Mustang", 35)
println(car.getNumberOfWheels()) // 4 // Car 클래스에 설정한 상수 4.
println(Vehicle.isDoubleTrack(car)) // true // 헬퍼 메소드 isDoubleTrack()의 조건문 불리언 리턴. 동행 객체 내 상수로 설정한 더블 트랙 자동차의 바퀴 수 3개 보다 Car 클래스에서 할당한 바퀴수 4개가 큰게 맞아서 true 리턴. getNumberOfWheels(car) = car.getNumberOfWheels() > DOUBLE_TRACK_AMOUNT_OF_WHEELS
println(car.isAntique()) // true // isAntique() 조건문 차의 수명이 30년이 넘어서 true 리턴.
}
fun companion_Object_Implementing_Vehicle(){
val bicycle = VehicleImplementedInCompanionObject.Bicycle
println(bicycle.getNumberOfWheels()) // 2 // 인터페이스 메서드 getNumberOfWheels()에 할당된 자전서 바퀴수 2.
println(Vehicle.isDoubleTrack(bicycle)) // false // 인터페이스 내 생성된 동행객체 메서드 isDoubleTrack(bicycle) = bicycle.getNumberOfWheels() > DOUBLE_TRACK_AMOUNT_OF_WHEELS 자전거 바퀴 2개가 더블 트랙 바퀴 수 3개보다 작으니까 false 리턴.
}
implementing_Vehicle()
companion_Object_Implementing_Vehicle()
}
Car 클래스는 Vehicle 인터페이스를 구현하고 있다. Car 클래스 내에서 동행객체가 새로 생성됐는데 인터페이스에서 생성됐던 동행객체에 영향을 주지 않는다.
프린트 해본 결과, car객체, bicycle객체 모두 인터페이스 내 getNumberOfWheels() 메서드에 접근하는 것에 차이가 없었다.
하지만, Car class로 여러개의 인스턴스를 생성할 수 있지만 VehicleImplementedInCompanionObject.Bicycle은 언제나 같은 싱글톤 인스턴스만 참조한다.
interface PlayingCard {
abstract fun getCardNumber(): String
fun getCardKing(): Int
companion object {
const val DIAMOND: Int = 3
const val HEART: Int = 2
fun winner(playingcard : PlayingCard) = playingcard.getCardKing() == 1 // king 카드를 가지고 있으면 1 아니면 0
}
}
class User1(val age: Int): PlayingCard {
override fun getCardNumber() = "3, 4, King"
override fun getCardKing() = 1
fun ageLimit() = age > 20
}
class User2(val age: Int): PlayingCard {
override fun getCardNumber() = "1, 10, Queen"
override fun getCardKing() = 0
fun ageLimit() = age > 20
}
fun main(args: Array<String>) {
fun userOne() {
val user1 = User1(38)
println(user1.ageLimit()) // true // 성인이어서 true
println(PlayingCard.HEART) // 2
println(PlayingCard.DIAMOND) //
println(PlayingCard.winner(user1)) // true // king card를 갖고 있어 1이므로 true 리턴.
}
fun userTwo() {
val user2 = User2(17)
println(user2.ageLimit()) // false // 미성년자이므로 false
}
userOne()
userTwo()
}
인터페이스의 장점
선언과 구현이 분리되어 있다.
느슨히 결합되어 있어 유지보수 하기 편하다.
중단점 찍어서 벌레 누르기
https://www.linkedin.com/pulse/abstract-classes-interfaces-kotlin-complete-guide-sagar-malhotra
https://www.baeldung.com/kotlin/companion-objects-interfaces