상속보다 구성이 필요한 이유는 무엇입니까?

우리는 OOP 세계에서 클래스를 구성하고 설계하는 방법에 주의해야 합니다. 간단한 응용 프로그램이 있거나 MVP 프로젝트를 구축하는 경우 코드가 짧고 실행 가능해야 하므로 이 주제에 전혀 신경쓰지 않을 것입니다. 그러나 우리는 다른 블로그 포스트를 위해 그것을 남겨둘 것입니다. 이제 이 두 가지 개념이 무엇인지 정의해 봅시다.

상속으로 시작



상속은 하나의 자식 클래스(하위 클래스)가 부모 클래스(슈퍼 클래스)로부터 모든 것을 물려받는 OOP의 개념입니다. 우리가 모든 것을 말할 때 그것이 의미하는 것은 해당 슈퍼 클래스의 속성과 기능입니다. 가장 좋은 것은 좋은 예를 제시하는 것입니다.

open class Animal {
 fun eat() {
    println("Njam njam")
  }
}

class Dog: Animal() {
  fun bark() {
    println("Woof!")
  }
  fun run() {
    println("Running..")
  }
}

class Cat: Animal() {
  fun meow() {
    println("Meow!")
  }
  fun jump() {
    println("Jumping..")
  }
}

fun main() {
  val goofy = Dog()
  println("Goofy wants to eat ${goofy.eat()}")

  val dizzie = Cat()
  println("Dizzie wants to eat ${dizzie.eat()}")
}


Dog 및 Cat 하위 클래스의 상위 클래스로 Animal 클래스가 있습니다. 그리고 이것은 훌륭합니다. 우리는 Animal 클래스에서 eat() 메서드를 상속했습니다.

이제 프로젝트의 요구 사항이 변경되어 집 주변을 청소해야 하는 로봇 개와 음악을 연주하는 다른 로봇을 원하는 사람이 있습니다!
아 그렇군요... 자, 상속을 이용해서 위와 같은 것을 정의해 봅시다.

open class Robot {
  fun stop() {
    println("Stopping")
  }

  fun move() {
    println("Moving")
  }
}

class DogRobot : Robot() {
  fun bark() {
    println("Woof!")
   }
  fun clean() {
    println("Cleaning around the house")
  }
}

class MusicRobot: Robot() {
  fun playMusic() {
    println("LalaLalLa")
  }
}

fun main() {
 val goofyRobot = DogRobot()
  println("Robot is ${goofyRobot.clean()}")
  println("Robot is ${goofyRobot.move()}")

  val musicRobot = MusicRobot()
  println("Robot playing ${musicRobot.playMusic()}")
  println("Stopping robot... ${musicRobot.stop()}")
}


우리는 지금 우리의 디자인을 가지고 있습니다. 모든 것이 멋져 보이고 갑자기, 어때? 요구 사항이 다시 변경되었습니다.
클라이언트는 짖고, 게임하고, 음악을 듣고, 요리하고, 집 주변을 청소할 수 있는 로봇을 요구합니다. 🙈

구조 구성.



컴포지션은 "외부에서"개체를 구성하고 구성하는 대신 다른 클래스에서 아무것도 상속하지 않는 개념입니다. 예를 보자:

class SuperRobot(
  private val dogRobot: DogRobot,
  private val musicalRobot: MusicRobot
) {
  fun playMusic() {
    println("Super robot will play some old school music: ${musicalRobot.playMusic()}")
  }
  fun bark() {
    println("Barking around the house ${dogRobot.bark()}")
  }
  fun clean() {
    println("Cleaning the house... ${dogRobot.clean()}")
  }
 }

fun main() {
  val superRobot = SuperRobot(
   dogRobot = DogRobot(),
   musicalRobot = MusicRobot()
 )
  println("Playing music: ${superRobot.playMusic()}")
  println("Barking: ${superRobot.bark()}")
  println("Cleaning: ${superRobot.clean()}")
}


Kotlin은 다중 상속을 지원하지 않기 때문에 상속 개념으로 Kotlin에서 이를 달성하는 것은 불가능합니다.

상속의 단점은 다음과 같습니다.
  • 하나의 클래스만 확장할 수 있습니다
  • .
  • 존중해야 하는 하위 클래스에 대한 계약을 설정하고 있습니다
  • .
  • 부모 클래스
  • 에서 모든 것을 가져옵니다.

    상속보다 컴포지션을 사용할 때의 장점:
  • 구성은 클래스 구현에 전혀 의존하지 않고 외부 관찰 가능 항목에만 의존하기 때문에 더 안전합니다.
  • 구성을 사용하면 더 유연해집니다. 상속할 때는 모든 것을 가져가지만 구성할 때는 선택할 수 있습니다.
    우리가 건설에 필요한 것.
  • 일부 메서드가 사용되는 클래스를 이미 알고 있기 때문에 구성을 사용한 단위 테스트가 더 쉽습니다.

  • 요약



    OOP의 일반적인 규칙은 상속보다 구성을 사용하는 것입니다. 꼭 필요한 경우와 하위 클래스가 존중해야 하는 엄격한 계약이 필요한 경우에만 상속을 사용하십시오. 다른 경우에는 구성을 위해 노력하십시오.
    기억하기 쉬운 것은 다음과 같습니다.
  • 클래스가 "is"인 경우 상속을 사용합니다.
  • 클래스가 "has"인 경우 구성을 사용합니다.

  • 행복한 코딩 :)

    좋은 웹페이지 즐겨찾기