λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°
πŸ“š Kotlin

[Effective Kotlin] μ•„μ΄ν…œ 32. μƒμ„±μž λŒ€μ‹  νŒ©ν† λ¦¬ ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜λΌ

by GroovyArea 2023. 1. 29.

μžλ°”λ₯Ό κ³΅λΆ€ν•˜λ©° κ°€μž₯ 의미 있게 읽은 책은 [μ΄νŽ™ν‹°λΈŒ μžλ°”]이닀. 

μžλ°”λ₯Ό λ§Œλ“  κ°œλ°œμžκ°€ 직접 μ§‘ν•„ν•œ μ±…μ΄λ―€λ‘œ, μžλ°”λ₯Ό μžλ°”λ‹΅κ²Œ μ‚¬μš©ν•˜λŠ” 방법이 μ•„μ£Ό λͺ…ν™•ν•˜κ²Œ μ„€λͺ…λ˜μ–΄ μžˆλ‹€.

κ°€μž₯ 첫 챕터인 'μƒμ„±μž λŒ€μ‹  νŒ©ν† λ¦¬ λ©”μ†Œλ“œλ₯Ό μ‚¬μš©ν•˜λΌ'λΌλŠ” μ•„μ΄ν…œμ„ ꡉμž₯히 의미 있게 읽게 λ˜μ—ˆκ³ , κ·Έ λ‚΄μš©μ„ μ½”λ“œλ₯Ό μž‘μ„±ν•  λ•Œ μ• μš©ν–ˆμ—ˆλ‹€.

 

코틀린도 μžλ°”μ˜ 이점을 κ·ΈλŒ€λ‘œ κ°€μ Έκ°„ μ–Έμ–΄μ΄λ―€λ‘œ, λΉ„μŠ·ν•˜κ²Œ 적용 λ˜λŠ” 뢀뢄이 μžˆμ„μ§€λ₯Ό 생각해 λ΄€λ‹€.

νšŒμ‚¬μ— λ“€μ–΄κ°€μ„œ 코틀린을 배우고 μ½”λ“œλ₯Ό μž‘μ„±ν•˜λ©΄μ„œ, κ°€μž₯ λˆˆμ— λ„μ—ˆλ˜ 뢀뢄이 dto 객체λ₯Ό λ§€ν•‘ν•˜λŠ” λΆ€λΆ„μ΄μ—ˆκ³ , νŒ©ν† λ¦¬ λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•˜λ©΄ μ–΄λ–¨κΉŒλΌλŠ” 생각을 ν–ˆλ‹€.

 

코틀린을 μ‚¬μš©ν•˜λŠ” λΆ„λ“€κ³Ό ꡬ글링을 톡해 μžλ°”μ™€ λ™μΌν•˜κ²Œ νŒ©ν† λ¦¬ λ©”μ„œλ“œλ₯Ό λ§Žμ΄λ“€ μ‚¬μš©ν•œλ‹€λŠ” 정보λ₯Ό μ–»μ—ˆκ³ , κ·ΈλŒ€λ‘œ μ μš©ν–ˆμ—ˆλ‹€.

 

μ΄νŽ™ν‹°λΈŒ μ½”ν‹€λ¦° 책을 펼치며 λͺ©μ°¨λ₯Ό ν›‘μ—ˆμ„ λ•Œ 이 챕터가 λˆˆμ— λ„μ—ˆκ³ , λ‚΄κ°€ μ•Œλ˜ 정보와 λΉ„κ΅ν•˜λ©° 읽으면 μž¬λ°Œκ² λ‹€λŠ” 생각을 ν–ˆκ³  λΉ„λ‘œμ†Œ 읽게 λ˜μ—ˆλ‹€. κ·Έ λ‚΄μš©μ„ 정리해 λ³Έλ‹€.

 

νŒ©ν† λ¦¬ ν•¨μˆ˜μ˜ 이점 

μƒμ„±μžμ˜ 역할을 λŒ€μ‹ ν•œλ‹€.

 

μƒμ„±μžμ™€ λ‹€λ₯΄κ²Œ ν•¨μˆ˜μ— 의미 μžˆλŠ” 이름을 뢙일 수 μžˆλ‹€.

κ°€λ Ή 객체λ₯Ό μƒμ„±ν•˜κΈ° μœ„ν•΄ ν•„μš”ν•œ νŒŒλΌλ―Έν„°κ°€ 무엇인지 λͺ…μ‹œλ₯Ό ν•  수 μžˆλ‹€λŠ” 점이닀.

 

이λ₯Ό ν…Œ λ©΄,

class ArrayList {

	companion object {
    	
        fun withSize(size: Int) : ArrayList {
        	return //...
        }
    }
}

ArrayList 객체λ₯Ό μƒμ„±ν•˜κΈ° μœ„ν•œ withSize() νŒ©ν† λ¦¬ ν•¨μˆ˜λŠ” μ‚¬μ΄μ¦ˆλ₯Ό νŒŒλΌλ―Έν„°λ‘œ λ°›λŠ” 객체λ₯Ό μ œκ³΅ν•œλ‹€λŠ” 의미λ₯Ό λͺ…ν™•ν•˜κ²Œ μ•Œ 수 μžˆλ‹€.

 

λ˜ν•œ, ν•¨μˆ˜κ°€ μ›ν•˜λŠ” ν˜•νƒœμ˜ νƒ€μž…μ„ 리턴할 수 μžˆλ‹€.

κ°€λ Ή listof()λΌλŠ” ν•¨μˆ˜λ₯Ό λ– μ˜¬λ Έμ„ λ•Œ, List μΈν„°νŽ˜μ΄μŠ€ νƒ€μž…μ„ return ν•œλ‹€λŠ” μ μ—μ„œ κ·Έ 의미λ₯Ό μ½”ν‹€λ¦° λΌμ΄λΈŒλŸ¬λ¦¬κ°€ μΆ©μ‘±μ‹œν‚€κ³  μžˆλ‹€.

 

호좜될 λ•Œλ§ˆλ‹€ μƒˆ 객체λ₯Ό λ§Œλ“€ ν•„μš”κ°€ μ—†λ‹€.

μ‹±κΈ€ν„΄ 객체λ₯Ό μƒμ„±ν•œλ‹€κ±°λ‚˜, 캐싱을 μ΄μš©ν•  μˆ˜κ°€ μžˆλ‹€.

객체 생성이 λΆˆκ°€λŠ₯ν•  경우, null을 return ν•  수 μžˆλ‹€.

이λ₯Ό ν…Œ λ©΄, Connection.createOrNull() λ“±λ“±..

 

μ‘΄μž¬ν•˜μ§€ μ•ŠλŠ” 객체λ₯Ό return ν•  μˆ˜λ„ μžˆλ‹€.

μ•žμœΌλ‘œ λ§Œλ“€μ–΄μ§ˆ 객체λ₯Ό μ‚¬μš©ν•˜κ±°λ‚˜ ν”„λ½μ‹œ 객체λ₯Ό μ‚¬μš©ν•  수 μžˆλ‹€.

 

객체 외뢀에 νŒ©ν† λ¦¬ ν•¨μˆ˜λ₯Ό μ μš©ν•  수 μžˆλ‹€.

κ°€μ‹œμ„± 쑰절이 κ°€λŠ₯ν•œ 것이 μž₯점이며, 같은 파일 ν˜Ήμ€ 같은 λͺ¨λ“ˆμ—μ„œλ§Œ μ ‘κ·Όν•˜κ²Œ 지정할 수 μžˆλ‹€.

 

νŒ©ν† λ¦¬ ν•¨μˆ˜λŠ” μƒμ„±μžλ₯Ό λ§Œλ“€κΈ° μœ„ν•œ λ³΅μž‘ν•œ 객체도 λ§Œλ“€ 수 μžˆλ‹€.

λ˜ν•œ, 무쑰건 ν˜ΈμΆœλ˜λŠ” μƒμ„±μžλ₯Ό μ›ν•˜λŠ” μ‹œκΈ°μ— ν˜ΈμΆœν•  수 μžˆλ‹€.

 

이처럼 μž₯점이 정말 λ§Žλ‹€.

μ½”ν‹€λ¦°μ—μ„œ νŒ©ν† λ¦¬ ν•¨μˆ˜λ₯Ό μƒμ„±ν•˜λŠ” 방법을 μ•Œμ•„λ³΄μž.

 

Companion νŒ©ν† λ¦¬ ν•¨μˆ˜

μ½”ν‹€λ¦°μ—μ„œ νŒ©ν† λ¦¬ ν•¨μˆ˜λ₯Ό μ •μ˜ν•˜λŠ” κ°€μž₯ 일반적인 방법이닀.

class MyLinkedList<T>(
	val head: T,
    val tail: MyLinkedList<T>?
) {
	
    companion object {
    	
        fun <T> of(vararg elements: T) : MyLinkedList<T>? {
        	// ...
        }
    }
}

κ°€μž₯ μ΅μˆ™ν•œ 방법이닀.

 

μ½”ν‹€λ¦°μ—μ„œλŠ” interface에도 companion objectλ₯Ό μ‚¬μš©ν•  수 μžˆμ–΄ λ™μΌν•˜κ²Œ νŒ©ν† λ¦¬ ν•¨μˆ˜λ₯Ό μ„ μ–Έν•  수 μžˆλ‹€.

class MyLinkedList<T>(
	val head: T,
    val tail: MyLinkedList<T>?
): MyList<T> {
	// ...
}

interface MyList<T> {
	//...
    
    
    companion object {
    	fun <T> of(vararg elements: T) : MyList<T>? {
        	// ...
        }
    }
}

val list = MyList.of(3,4,5,6)

μ°Έ ν˜μ‹ μ μ΄ 고만.

 

νŒ©ν† λ¦¬ ν•¨μˆ˜ λͺ… κ·œμ•½

from : νŒŒλΌλ―Έν„°λ₯Ό ν•˜λ‚˜ λ°›κ³ , ν•΄λ‹Ή νƒ€μž…μ˜ μΈμŠ€ν„΄μŠ€ ν•˜λ‚˜ return

val date = Date.from(instatnt)

 

of : νŒŒλΌλ―Έν„°λ₯Ό μ—¬λŸ¬ 개 λ°›κ³ , ν†΅ν•©ν•˜μ—¬ μΈμŠ€ν„΄μŠ€λ₯Ό return

val cards : Set <Rank> = EnumSet.of(JACK, QUEEN, KING)

 

valueOf : from, of와 λΉ„μŠ·ν•¨. 의미λ₯Ό 쑰금 더 μ‰½κ²Œ 읽을 수 μžˆλŠ” ν•¨μˆ˜

val prime : BigInteger = BigInteger.valueOf(Integer.MAX_VALUE)

 

instance, getInstance : μ‹±κΈ€ν„΄ μΈμŠ€ν„΄μŠ€ ν•˜λ‚˜λ₯Ό return

val connection = Connection.getInstance(parameter)

 

createInstance, newInstance : getInstance와 동일, 싱글턴이 μ•„λ‹˜. ν˜ΈμΆœν•  λ•Œλ§ˆλ‹€ μƒˆλ‘œμš΄ μΈμŠ€ν„΄μŠ€λ₯Ό return

val newPerson = Person.newInstance(age, name)

 

getType : getInstance와 동일, νŒ©ν† λ¦¬ ν•¨μˆ˜κ°€ λ‹€λ₯Έ ν΄λž˜μŠ€μ— μžˆμ„ λ•Œ μ‚¬μš©, νƒ€μž…μ€ νŒ©ν† λ¦¬ ν•¨μˆ˜μ—μ„œ return ν•˜λŠ” νƒ€μž…

val fs: FileStore = Files.getFileStore(path)

 

newType : newInstance와 동일,

val br : BufferedReader = Files.newBufferedReader(path)

 

 

이와 같이 κ·œμ•½μ„ 지킀며 λ§Œλ“€λ©΄ 쒋을 것 κ°™λ‹€.

λ‚˜μ²˜λŸΌ μ½”ν‹€λ¦° μž…λ¬Έν•œ 지 μ–Όλ§ˆ λ˜μ§€ μ•Šμ€ κ°œλ°œμžλŠ” μ½”ν‹€λ¦°μ˜ companion objectλ₯Ό static처럼 μ‚¬μš©ν•˜λŠ” κ²½ν–₯이 μžˆλŠ”λ°,

μœ„μ²˜λŸΌ c.o도 μ—„μ—°ν•œ κ°μ²΄μ΄λ―€λ‘œ interfaceλ₯Ό 상속받아 κ΅¬ν˜„ν•  수 μžˆλ‹€.

이λ₯Ό 잘 ν™œμš©ν•˜μ—¬ 캐싱을 κ΅¬ν˜„ν•˜κ±°λ‚˜ ν…ŒμŠ€νŠΈλ₯Ό μœ„ν•œ κ°€μ§œ 객체λ₯Ό 생성할 수 μžˆμ„ 것이닀.

 

μ½”ν‹€λ¦° νŒ€ μ œν’ˆ κ΅¬ν˜„μ„ 자주 μ°Έκ³ ν•΄μ„œ μ‚¬μš© 방법을 λͺ…ν™•νžˆ 이해해야겠닀.

 

 

ν™•μž₯ νŒ©ν† λ¦¬ ν•¨μˆ˜

이미 companion 객체가 μ‘΄μž¬ν•  λ•Œ, 이 객체의 ν•¨μˆ˜μ²˜λŸΌ μ‚¬μš©ν•˜λŠ” νŒ©ν† λ¦¬ ν•¨μˆ˜λ₯Ό λ§Œλ“€ κ²½μš°μ— μ‚¬μš©ν•œλ‹€.

ν™•μž₯ ν•¨μˆ˜λ₯Ό μ΄μš©ν•΄μ„œ!

 

interface Tool {

	companion object {
    	//....
    }
}

fun Tool.Companion.createBigTool(/*...*/) : BigTool {
	//...
}

Tool.createBigTool()

이런 μ‹μœΌλ‘œ companion 객체λ₯Ό 직접 μˆ˜μ •ν•˜μ§€ μ•Šκ³ , μ™ΈλΆ€ νŒŒμΌμ—μ„œ ν™•μž₯ νŒ©ν† λ¦¬λ₯Ό λ”°λ‘œ μ •μ˜ν•΄μ„œ μ‚¬μš©ν•  수 μžˆλ‹€.

μ°¨μ•”λ‚˜~

λ¬Όλ‘  ν™•μž₯ν•˜λ €λ©΄ ν™•μž₯μ²˜μ— companion이 μ •μ˜λ˜μ–΄ μžˆμ–΄μ•Όκ² λ‹€.

 

 

ν†±λ ˆλ²¨ νŒ©ν† λ¦¬ ν•¨μˆ˜

λŒ€ν‘œμ μΈ μ˜ˆμ‹œλ‘œ, mapof, listof, setof 등이 μžˆλ‹€.

 

κ°€λ Ή listof(1,2,3) 이 κΈ°μ‘΄ List.of(1,2,3) 보닀 가독성이 훨씬 μ’‹κΈ° λ•Œλ¬Έμ—, ν†±λ ˆλ²¨ ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•œλ‹€.

ν•˜μ§€λ§Œ, ν†±λ ˆλ²¨ ν•¨μˆ˜λ₯Ό λ§Œλ“€ λ•Œ ν•¨μˆ˜μ˜ 이름을 클래슀 λ©”μ„œλ“œ μ΄λ¦„μ²˜λŸΌ 짓지 말자.

μ‹ μ€‘ν•˜κ²Œ μƒκ°ν•΄μ„œ 이름을 μ§€μ •ν•˜μž.

 

 

κ°€μ§œ μƒμ„±μž

class A

val A = A()

 

μ½”ν‹€λ¦°μ˜ μƒμ„±μžλŠ” ν†±λ ˆλ²¨ ν•¨μˆ˜μ™€ 같은 ν˜•νƒœμ΄λ‹€.

 

ν†±λ ˆλ²¨ ν•¨μˆ˜μ²˜λŸΌ μƒμ„±μž ν•¨μˆ˜λ„ μ°Έμ‘°ν•  수 μžˆλ‹€.

val reference: () -> A = ::A

 

일반적으둜 μƒμ„±μžμ™€ ν•¨μˆ˜λ₯Ό κ΅¬λΆ„μ§“λŠ” 방법은 λŒ€λ¬Έμž μ‹œμž‘ μœ λ¬΄μ΄λ‹€.

 

ν•˜μ§€λ§Œ,

List(4) ??

 

μΈν„°νŽ˜μ΄μŠ€κ°€ μ–΄λ–»κ²Œ μƒμ„±μžλ₯Ό 가지지?

 

코틀린이 μ œκ³΅ν•˜λŠ” λΌμ΄λΈŒλŸ¬λ¦¬μ—μ„œλŠ” κ°€λŠ₯ν•˜λ‹€.

μ΄λŸ¬ν•œ ν†±λ ˆλ²¨ ν•¨μˆ˜λŠ” μƒμ„±μžμ²˜λŸΌ 보이고, μƒμ„±μžμ²˜λŸΌ μž‘λ™ν•œλ‹€.

그와 λ™μ‹œμ— νŒ©ν† λ¦¬ ν•¨μˆ˜μ˜ 이점을 κ°–λŠ”λ‹€.

이것도 μ—„μ—°ν•œ νŒ©ν† λ¦¬ ν•¨μˆ˜μ΄λ―€λ‘œ, κ°€μ§œ μƒμ„±μžλΌ λΆˆλ¦¬μš΄λ‹€.

 

데게,

μΈν„°νŽ˜μ΄μŠ€λ₯Ό μœ„ν•œ μƒμ„±μžλ₯Ό λ§Œλ“€κ³  싢을 경우

refied νƒ€μž… 인자λ₯Ό κ°–κ²Œ ν•˜κ³  싢을 경우 

μƒμ„±ν•œλ‹€.

 

 

정리

νŒ©ν† λ¦¬ ν•¨μˆ˜λ₯Ό λ§Œλ“€ 수 μžˆλŠ” λ‹€μ–‘ν•œ λ°©λ²•λ“€μ˜ νŠΉμ§•μ„ λͺ…ν™•νžˆ μ΄ν•΄ν•˜κ³  μ‚¬μš©ν•˜μž.

κ°€μž₯ 일반적인 방법은 companion object λ₯Ό μ΄μš©ν•˜λŠ” 방법이닀.

μžλ°”μ˜ 정적 νŒ©ν† λ¦¬ λ©”μ„œλ“œ νŒ¨ν„΄κ³Ό μœ μ‚¬ν•˜κ³  μ•ˆμ „ν•˜κ³  μ΅μˆ™ν•˜κ²Œ 코틀린이 κ³„μŠΉν–ˆκΈ° λ•Œλ¬Έμ΄λ‹€.

 

λ°˜μ‘ν˜•