Dart에서의 상속과 믹싱: extends, with, implements

2024. 6. 21. 20:37Flutter/Dart Language

반응형

 

Dart는 객체 지향 프로그래밍(OOP) 언어로, 클래스와 인터페이스를 통해 다양한 기능을 구현할 수 있습니다.

Dart에서는 상속과 믹싱을 통해 클래스 간의 관계를 정의하며, 각각의 키워드(extends, with, implements)는 다른 목적과 사용 방식을 가지고 있습니다.

이들의 차이점과 각각의 사용법을 살펴보겠습니다.

1. extends

extends 키워드는 클래스가 다른 클래스를 상속받을 때 사용됩니다. 상속은 클래스 간의 계층 구조를 형성하며, 하위 클래스(subclass)는 상위 클래스(superclass)의 모든 속성과 메서드를 상속받습니다.

1.1 기본 구조

class Animal {
  String name;

  Animal(this.name);

  void eat() {
    print('$name is eating.');
  }
}

class Dog extends Animal {
  String breed;

  Dog(String name, this.breed) : super(name);

  void bark() {
    print('$name is barking.');
  }
}
  • Animal 클래스는 name 속성과 eat() 메서드를 가지고 있습니다.
  • Dog 클래스는 Animal 클래스를 상속받아 name 속성과 eat() 메서드를 사용할 수 있으며, 추가로 breed 속성과 bark() 메서드를 가집니다.

1.2 장점

  • 코드 재사용: 공통 기능을 상위 클래스에서 정의하고 하위 클래스에서 재사용할 수 있습니다.
  • 계층 구조: 클래스 간의 명확한 계층 구조를 형성하여 코드를 체계적으로 관리할 수 있습니다.
  • 확장성: 기존 클래스의 기능을 확장하거나 수정할 수 있습니다.

1.3 주의점

  • 다중 상속 제한: Dart는 단일 상속만을 지원하므로 하나의 클래스는 하나의 상위 클래스만을 상속받을 수 있습니다.
  • 긴밀한 결합: 상속은 클래스들 간의 긴밀한 결합을 초래할 수 있으므로, 상속이 적절한지 신중하게 고려해야 합니다.

2. with

with 키워드는 mixin을 클래스에 적용할 때 사용됩니다. mixin은 클래스에 다양한 기능을 추가할 수 있는 방법을 제공하며, 계층 구조를 형성하지 않고 클래스들의 기능을 조합할 수 있습니다.

2.1 기본 구조

mixin Flyable {
  void fly() {
    print('Flying...');
  }
}

mixin Swimable {
  void swim() {
    print('Swimming...');
  }
}

class Duck with Flyable, Swimable {
  String name;

  Duck(this.name);
}
  • Flyable mixin은 fly() 메서드를, Swimable mixin은 swim() 메서드를 정의합니다.
  • Duck 클래스는 with 키워드를 사용하여 Flyable과 Swimable mixin을 추가하여 fly()와 swim() 메서드를 포함하게 됩니다.

2.2 장점

  • 다양한 기능 결합: 여러 개의 mixin을 사용하여 클래스에 필요한 기능을 조합할 수 있습니다.
  • 계층 구조 없음: mixin은 클래스 간의 계층 구조를 형성하지 않기 때문에 코드의 유연성을 높이고 중복을 줄일 수 있습니다.
  • 다중 상속 대안: Dart에서 다중 상속을 지원하지 않기 때문에 mixin을 사용하여 다수의 클래스에서 기능을 가져올 수 있습니다.

2.3 주의점

  • 명칭 충돌: mixin을 사용할 때 여러 클래스에서 동일한 이름의 메서드를 사용하면 명칭 충돌이 발생할 수 있습니다. 이를 방지하기 위해 별칭을 사용하거나 메서드 이름을 변경해야 할 수 있습니다.
  • 복잡성 증가: 너무 많은 mixin을 사용하면 코드가 복잡해질 수 있으므로, 필요한 기능만을 mixin으로 추출하는 것이 중요합니다.

3. implements

implements 키워드는 클래스가 인터페이스를 구현할 때 사용됩니다. 인터페이스는 클래스가 반드시 구현해야 하는 메서드를 정의하며, 클래스는 인터페이스의 모든 메서드를 구현하여야 합니다.

3.1 기본 구조

abstract class Printable {
  void print();
}

class Book implements Printable {
  String title;
  String author;

  Book(this.title, this.author);

  @override
  void print() {
    print('Printing $title by $author');
  }
}
  • Printable 인터페이스는 print() 메서드를 선언합니다.
  • Book 클래스는 implements 키워드를 사용하여 Printable 인터페이스를 구현하고, print() 메서드를 구현합니다.

3.2 장점

  • 명확한 계약: 인터페이스는 클래스가 반드시 구현해야 하는 메서드를 명시하여 코드의 일관성을 유지할 수 있습니다.
  • 유연성: 인터페이스를 사용하면 클래스가 서로 다른 계층 구조에 속해도 동일한 메서드를 구현할 수 있습니다.

3.3 주의점

  • 모든 메서드 구현 필수: 인터페이스를 구현하는 클래스는 인터페이스에 정의된 모든 메서드를 구현하여야 합니다.
  • 추상화 수준 유지: 인터페이스의 추상화 수준을 적절히 유지하여 클래스 간의 관계를 명확히 해야 합니다.

4. 사용 시나리오

  • extends: 클래스 간의 계층 구조를 형성하고 코드를 재사용해야 할 때 사용합니다.
  • with: 다양한 기능을 하나의 클래스에 결합하거나 다중 상속을 대체할 때 사용합니다.
  • implements: 클래스가 반드시 구현해야 하는 메서드를 정의할 때 사용하며, 다양한 클래스 간의 관계를 명확히 할 때 유용합니다.

5. 결론

각 키워드인 extends, with, implements는 Dart에서 클래스 간의 관계를 정의하는 다양한 방법을 제공합니다.

적절한 상황에서 이를 사용하여 코드의 재사용성, 유지 관리성, 유연성을 높이는 것이 중요합니다.

상속은 계층 구조를 형성하고 코드를 재사용할 때 유용하며, mixin은 다양한 기능을 유연하게 결합할 수 있습니다.

인터페이스는 클래스가 반드시 구현해야 하는 메서드를 정의하여 코드의 일관성을 유지하는 데 도움을 줍니다.

 

 

수발가족을 위한 일기장 “나비일기장”

 

https://play.google.com/store/apps/details?id=com.maccrey.navi_diary_release

 

구글플레이 앱 배포의 시작! 비공개테스트 20명의 테스터모집을 위한 앱 "테스터 쉐어"

 

https://play.google.com/store/apps/details?id=com.maccrey.tester_share_release

 

Tester Share [테스터쉐어] - Google Play 앱

Tester Share로 Google Play 앱 등록을 단순화하세요.

play.google.com

카카오톡 오픈 채팅방

https://open.kakao.com/o/gsS8Jbzg

반응형