theme: apple-basic
layout: intro
highlighter: shiki
lineNumbers: true
"There should never be more than one reason for a class to change."
"There should never be more than one reason for a class to change."
"Software entities ... should be open for extension, but closed for modification."
"Software entities ... should be open for extension, but closed for modification."
"Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it."
open class Rectangle {
open var width = 0
open var height = 0
val area: Int
get() = this.width * this.height
}
class Square : Rectangle() {
override var width: Int
get() = super.width
set(width) {
super.width = width
super.height = width
}
override var height: Int
get() = super.height
set(height) {
super.width = height
super.height = height
}
}
fun calculateArea(r: Rectangle) {
r.width = 2
r.height = 3
assert(r.area == 6)
}
fun main() {
calculateArea(Rectangle())
calculateArea(Square())
}
"Many client-specific interfaces are better than one general-purpose interface."
interface Animal {
fun eat()
fun run(from: Where, to: Where)
fun fly(from: Where, to: Where)
}
class Eagle : Animal {
override fun eat() = println("### walk ###")
override fun run(from: Where, to: Where) = println("### run ###")
override fun fly(from: Where, to: Where) = println("### fly ###")
}
class Lion : Animal {
override fun eat() = println("### walk ###")
override fun run(from: Where, to: Where) = println("### run ###")
override fun fly(from: Where, to: Where) // 구현 필요 없음
}
interface Animal {
fun eat()
fun run(from: Where, to: Where)
fun fly(from: Where, to: Where)
}
interface Bird {
fun eat()
fun run(from: Where, to: Where)
fun fly(from: Where, to: Where)
}
interface Mammal {
fun eat()
fun run(from: Where, to: Where)
}
"Depend upon abstractions, [not] concretions."
class GasolineEngine {
val fuel = "gasoline"
}
class Car {
val engine = GasolineEngine()
}
class DieselEngine {
val fuel = "diesel"
}
class Car {
// val engine = GasolineEngine()
val engine = DieselEngine()
}
class DieselEngine {
val fuel = "diesel"
}
class Car {
val engine = DieselEngine()
}
class DieselEngine {
val fuel = "diesel"
}
class Car(val engine: DieselEngine) {
}
fun main() {
val dieselEngine = DieselEngine()
val car = Car(dieselEngine)
}
class DieselEngine {
val fuel = "diesel"
}
class Car {
val engine = null
private fun setEngine(engine: Engine) {
this.engine = engine
}
}
fun main() {
val dieselEngine = DieselEngine()
val car = Car()
car.setEngine(dieselEngine)
}
interface DieselEngineInjector {
fun inject(dieselEngine: DieselEngine)
}
class DieselEngine {
val fuel = "diesel"
}
class Car implements DieselEngineInjector {
val engine = null
override fun inject(dieselEngine: DieselEngine) {
this.engine = engine
}
}
fun main() {
val dieselEngine = DieselEngine()
val car = Car()
car.inject(dieselEngine)
}
생성자 주입 방식
메소드와 인터페이스를 통한 주입 방식
class GasolineEngine {
val fuel = "gasoline"
}
class DieselEngine {
val fuel = "diesel"
}
class Locator(
private val dieselEngine: DieselEngine,
private val gasolineEngine: GasolineEngine)
{
fun getGasolineEngine(): GasolineEngine {
return gasolineEngine
}
fun getDieselEngine(): DieselEngine {
return dieselEngine
}
companion object {
private var instance: Locator? = null
fun getInstance(locator: Locator) =
instance ?: Locator(dieselEngine, gasolineEngine).also {
instance = it
}
}
}
class Car {
val engine = Locator.getInstance().getDieselEngine
}
fun main() {
val dieselEngine = DieselEngine()
val gasolineEngine = GasolineEngine()
val locator = Locator(dieselEngine, gasolineEngine)
val car = Car()
}