kotlin

Kotlin class-03; Object, companion object, Generic

slow333 2023. 1. 14. 11:58

16. Object, companion object

    object 생성자 없이 객체를 만들어 , 출력만 있고 입력은 없음

    object 선언된 객체는 최초 사용시 자동으로 생성되며 이후 코드전체에서 공용으로 사용 가능

    프로그램이 종료되기 전까지 공통적으로 사용할 내용들을 묶어서 넣어

    class처럼 객체지향으로 코딩하고 싶지만 코드내에서 하나만 생성되는 공용객체가 필요?

    singleton pattern : 객체를 실행할 한번만 실행

-------------------------------------------------

object CarFactory {

    val cars = mutableListOf<Car>()

   

    fun makeCar(horsePower : Int, name : String) : Car {

        val car = Car(horsePower, name)

        cars.add(car)

        return car

    }

   

    fun carList(){

        for((i, j) in cars) {

            println("${i} , ${j}")

        }

    }

}

 

data class Car (val horsePower : Int, val name : String)

 

fun main () {

   

    val car1 = CarFactory.makeCar(100, "sonata")

    val car2 = CarFactory.makeCar(200, "santafe")

    println(car1)

    println(car2)

   

    println("${car2.horsePower} , ${car2.name}")

   

    println(CarFactory.cars.size.toString())

    println(CarFactory.carList())

}

-------------------------------------------------

fun main () {

    println(Counter.a)

    Counter.countUp()

    Counter.countUp()

   

    println(Counter.a)

   

    Counter.clear()

    println(Counter.a)   

   

    var c = FoodPoll("짜장")

    var d = FoodPoll("짬봉")

   

    c.vote()

    c.vote()

   

    d.vote()

   

    println("짜장 : ${c.count}")

    println("짬뽕 : ${d.count}")

    println("전체 : ${foodPoll.total}")

}

 

object Counter {

    var a = 0

    fun countUp(){

        a += 4

    }

    fun clear() {

        a = 0

    }

}

 

// 짜장, 짬뽕 좋아하는 것은 ???

class FoodPoll (val name: String) {

    companion object {

        var total = 0

    }

    var count = 0

    fun vote() {

        total++

        count++

    }

}

 

    Companion Object : 기존 class 안에도 object 만들 있음

·    class 속성(instance) 그대로 사용하면서 instance 공용 속성 함수를 뽑아서 만듦

·    private property or method 읽어 올수 있도록...

-------------------------------------------------

class Book private constructor (val id: Int, val name: String) {

   

    companion object BookFac : IdProvider { //이름을 적으면 사용시에도 이름을 써야함

        override fun getId() : Int {

            return 45

        }

        val 아이디 = 33

        val 이름 = "코트린 "

        fun create() = Book(아이디, 이름)

    }

}

 

interface IdProvider {

    fun getId() : Int

}

 

fun main() {

 

    val book = Book.create()  //     val book = Book.Companion.create()

    println("${book.id} : ${book.name}")

   

    val bookID = Book.BookFac.getId()

    println(bookID)

}

 

17. listener Anonymous Object

    observer : 이벤트가 일어나는 것을 감시하는 역할을 수행

·    시스템 또는 루틴에 의해서 발생하게 되는 동작들을 이벤트라고 부름

    함수로 직접 요청하지 안았지만 키의 입력, 터치의 발생, 데이터의 수신 (이벤트) 발생 마다 즉각적으로 처리할 있도록 만드는 프로그래밍 패턴을 옵저버 패턴이라고 부름

·    observer 패턴을 구현할 때는 2개의 class 필요

·    이벤트를 수신하는 class(class A)

·    이벤트를 발생시커 이를 알려주는 class(class B)

class A
함수를 불러라
(이벤트를 수신)
class B
“event 발생했습니다.”
(이벤트의 발생 전달)

 

A B 참조할 있지만 B A 참조할 없음 à 중간에 interface 끼워넣음

class A
“그거 좋구나 종은 내가 만들어 주마”
(이벤트를 수신)
class B
이제 클리되면 종을 울리겠습니다.”
(이벤트의 발생 전달)

이때 interface ‘observer’, kotlin에서는 ‘listener’라고

이렇게 이벤트를 넘겨주는 행위를 callback 이라고

-------------------------------------------------

/* 이벤트를 수신해서 출력하는 class EventPrinter

 * 5 배수 마다 알림을 보내는 class Counter

 * 두개를 연결한 interface EventListener */

fun main () {

    EventPrinter().start()

}

 

interface EventListener {

    fun onEvent(count: Int)

}

 

class Counter (var listener : EventListener) {

    fun count() {

        for(i in 1..50) {

            if (i % 5 == 0) listener.onEvent(i)

        }

    }

}

 

class EventPrinter : EventListener {

    override fun onEvent(count: Int) {

        print("${count} - ")

    }

   

    fun start() {

        val counter = Counter(this)

        /* this EventPrinter 객체 자신을 나타내지만 받는 쪽에서

         * 'EventListenet' 요구 했기 때문에 EventListener 구현부만 넘겨주게

         * 이를 객체지향의 다형성 이라고

         * 상속받아 만들어진 클레스는 수퍼 class 기능을 포함하여 제작되었으므로

         * 수퍼class에서 정의한 부분만 따로 정의해서 넘겨줄수 있음. 나중에 좀더 설명 */

        counter.count()

    }

}

 

/* EvnentPrinter EventListener 상속받지 않고

 * 임시로 만든 별도의 EventListener 객체를 대신 넘겨줄수 있음

 * 이를 '이름이 없는 객체' 하여 Anonymous Object라고 */

 

class EventPrinter {

    fun start() {

        val counter = Counter(object: EventListener {

            override fun onEvent(count: Int){

                print("${count} /")

            }

        })

        counter.count()

    }

    //이렇게 만들면 interface 구현한 객체를 코드 중간에도 즉시 생성하여 사용할 있음

}

 

18. class 다형성

    콜라는 콜라 자체로도 볼수 있니만 음료로도 보는 것이 다형성

    class Cola class Drink 상속받으면

·    instance of Cola네는 Drink 객체 공간과 Cola 추가 공간이 생성

 

instance of Cola
Drink 객체 공간
Cola 추가 공간

 

var a : Drink = Cola() // Drink 객체 공간만 사용

var b : Cola = Cola() // 모두 사용

 

    하위 class(Cola) 상위 자료형인 수퍼 class 변환하는 것을 Up-Casting

    Up-Casting instance 다시 하위 자료형으로 변환하는 것을 Down-Casting

·    Up-Casting 상위 자료형에 담으면 되지만

·    Down-Casting 별도의 연산자가 필요(as , is)

-    as 변수를 호환되는 자료형으로 변환해 주는 casting 연산자로 코드 내에서 사용할 경우

 

var a : Drink = Cola()

a as Cola // 즉시 자료형으로 변환해 주며

var b = a as Cola //변환된 결과를 반환 받아 변수에 넣을 있음

-    is 변수가 자료형에 호환되는 지를 확인 변환 해주는 캐스팅 연산자로 조건문 내에서 사용

var a : Drink = Cola()

if(a is Cola){ “ 안에서만 a Cola   }

----------------------------------------

fun main () {

    var a = Drink()

    a.drink()

   

    var b : Drink = Cola()

    b.drink()

   

    if (b is Cola){

        b.washDishes()

    }

   

    var c = b as Cola

    c.washDishes()

    b.washDishes()

}

 

open class Drink {

    var name = "음료"

    open fun drink() {

        println("${name} 마십니다.")

    }

}

 

class Cola : Drink() {

    var type = "콜라"

    override fun drink() {

        println("${name} 중에 ${type} 마십니다.")

    }

    fun washDishes(){

        println("${type}으로 설거지를 하자.")

    }

}

-------------------------------------------------

다형성은 class 상속관계에서 오는 instance 호환성을 적극 활용할 있는 기능으로 수퍼class 같은 instance 한번에 관리하거나 interface 구현하여 사용하는 코드에서도 이용되니 이해가 필요합니다.

 

19. Generic

    class 함수에서 사용하는 자료형을 외부에서 지정할 있는 기능

    class A 상속받은 class B : class instance 공용으로 사용하는 하나의 함수에 패러미터로 받으려면 ?

·    fun castingEx(var a: A) B 자동으로 A 캐스팅되면서 class 모두 함수의 패러미터로 사용할 있으나 캐스팅 연산을 거치는 것은 프로그램의 속도를 저하 시키는 단점이 있음

·    그래서 Generic이라는 개념이 나옴

    Generic 함수나 클래서를 선언 고정적인 자료형 대신 실제 자료형으로 대체되는 타입 패러미터를 받아 사용하는 방법.

·    타입 파라미터에 특정 자료형이 할당 되면 제너릭을 사용하는 모든 코드는 할당된 자료형으로 대체되어 컴파일 따라서 캐스팅 연산없이도 자료형을 그대로 사용할 있음

 

fun <T> genericFunc(param: T):T

class GenericClass <T> (var pref:T)

 

fun <Int> genericFunc(param: T):T

class GenericClass <Int> (var pref:T)

·    타입 파라미터의 이름은 class 이름과 규칙이 같지만 일반적으로 ‘Type’ 이니셜인 T 사용하는 것이 관례. 여러 개의 제너릭을 사용할 경우 <T, U, V> 추가적으로 사용하기도

·    또한 제너릭을 특정한 수퍼 class 상속받는 class 타입으로만 제한하려면 T 쓰고 수퍼 class이름을 명시하면됨<T:SuperClass>

·    이렇게 선언된 제너릭 사용법

fun <T> genericFunc<var param:T) { }

genericFunc(1)

-------------------------------------------------

fun main () {

    UsingGeneric<A>(A()).doShouting()

    UsingGeneric(B()).doShouting()

    UsingGeneric(C()).doShouting()

   

    doShouting(B())

}

 

fun <T: A> doShouting(t: T) {

    t.shout()

}

 

open class A {

    open fun shout() {

        println("A 소리침..")

    }   

}

class B : A() {

    override fun shout() {

        println("B 소리침***")

    }

}

class C : A() {

    override fun shout() {

        println("C 소리침***")

    }   

}

 

class UsingGeneric<T: A> (val t: T) {

    fun doShouting() {

        t.shout()

    }

}

'kotlin' 카테고리의 다른 글

Kotlin String  (0) 2023.01.14
Kotlin List  (0) 2023.01.14
Kotlin class-02  (0) 2023.01.14
Kotlin class-01  (0) 2023.01.14
Kotlin 기본 형, loop ,if  (0) 2023.01.14