이 글은 Dart 언어에서 추상 클래스와 인터페이스의 개념과 사용 방법을 설명하기 위해 작성되었습니다. 추상 클래스와 인터페이스를 사용하는 이유, 선언 및 구현 방법, 그리고 이를 통해 얻을 수 있는 코드의 재사용성과 유지보수성에 대해 이해할 수 있도록 정리해 보았습니다.
추상 클래스와 인터페이스
추상 클래스 (Abstract Class)
추상 클래스는 공통된 속성이나 메서드를 여러 클래스에서 공유하고 싶을 때 사용합니다. 즉, 기본 틀을 정의하고, 실제 구현은 이를 상속받은 클래스에서 하도록 합니다. 추상 클래스는 인스턴스를 만들 수 없고, 상속을 통해서만 사용할 수 있습니다.
추상 클래스 선언
abstract class Animal {
void sound(); // 추상 메서드, 구현이 없음
}
여기서 Animal 클래스는 추상 클래스입니다. sound 메서드는 추상 메서드로, 구현되지 않은 상태입니다.
추상 클래스 상속
class Dog extends Animal {
@override
void sound() {
print('Bark');
}
}
class Cat extends Animal {
@override
void sound() {
print('Meow');
}
}
Dog 와 Cat 클래스는 Animal 클래스를 상속받아 sound 메서드를 각각 구현합니다. 이제 이 클래스를 사용할 수 있습니다.
예시 코드 1.
void main() {
Dog dog = Dog();
dog.sound(); // Bark
Cat cat = Cat();
cat.sound(); // Meow
}
예시 코드 2.
아래 예시코드에서 Animal은 추상 클래스이며, eat()은 추상 메서드입니다. Dog 클래스는 Animal을 상속받아 eat() 메서드를 구현하고 있습니다. sleep() 메서드는 Animal 클래스에서 이미 구현되어 있으므로 Dog 클래스에서 별도로 구현하지 않아도 됩니다.
abstract class Animal {
String name;
void eat();
void sleep() {
print("$name is sleeping.");
}
}
class Dog extends Animal {
Dog(String name) {
this.name = name;
}
void eat() {
print("$name is eating.");
}
}
void main() {
Dog myDog = Dog("Buddy");
myDog.eat(); // "Buddy is eating." 출력
myDog.sleep(); // "Buddy is sleeping." 출력
}
인터페이스 (Interface)
인터페이스는 클래스가 특정 메서드들을 반드시 구현하도록 강제하는 역할을 합니다. Dart에서는 모든 클래스가 인터페이스 역할을 할 수 있습니다. 특별히 인터페이스를 구현하기 위해서는 implements 키워드를 사용합니다.
인터페이스 선언
class Printable {
void (); // 메서드 정의만 있음, 구현 없음
}
Printable 클래스는 인터페이스 역할을 합니다.
인터페이스 구현
class Document implements Printable {
@override
void () {
('Document is being printed');
}
}
class Image implements Printable {
@override
void () {
('Image is being printed');
}
}
Document와 Image 클래스는 Printable 인터페이스를 구현하여 printMessage 메서드를 정의합니다.
예시 코드 1.
void () {
Document doc Document();
doc.(); // Document is being printed
Image img Image();
img.(); // Image is being printed
}
예시 코드 2.
class Flyable {
void fly();
}
class Walkable {
void walk();
}
class Bird implements Flyable, Walkable {
void fly() {
print("Bird is flying.");
}
void walk() {
print("Bird is walking.");
}
}
void main() {
Bird myBird = Bird();
myBird.fly(); // "Bird is flying." 출력
myBird.walk(); // "Bird is walking." 출력
}
위 예시에서 Flyable과 Walkable은 인터페이스 역할을 하는 일반 클래스입니다. Bird 클래스는 이 두 인터페이스를 implements하여 구현하고 있습니다.
추상 클래스와 인터페이스의 차이점
- 추상 클래스는 여러 개를 상속받을 수 없습니다. 즉, 한 클래스는 하나의 추상 클래스만 상속받을 수 있습니다.
- 인터페이스는 여러 개를 구현할 수 있습니다. 즉, 한 클래스는 여러 개의 인터페이스를 implements할 수 있습니다.
- 추상 클래스는 구현할 메서드를 포함할 수 있습니다. 인터페이스는 메서드 정의만 가능합니다.
실습 예제
다중 인터페이스 구현 예제
class Scannable {
void scan();
}
class Faxable {
void fax();
}
class MultiFunctionPrinter implements Scannable, Faxable {
@override
void scan() {
print('Scanning document...');
}
@override
void fax() {
print('Faxing document...');
}
}
void main() {
MultiFunctionPrinter mfp = MultiFunctionPrinter();
mfp.scan(); // Scanning document...
mfp.fax(); // Faxing document...
}
MultiFunctionPrinter 클래스는 Scannable과 Faxable 인터페이스를 구현하여 각각의 메서드를 정의하고 있습니다.
이처럼 추상 클래스와 인터페이스를 활용하면 코드의 재사용성과 유지보수성을 높일 수 있습니다. 상속과 구현을 통해 공통된 기능을 추상화하고, 구체적인 동작은 개별 클래스에서 정의할 수 있습니다. 이를 통해 코드의 중복을 줄이고, 모듈화된 구조를 만들 수 있습니다.
'프로그래밍 언어 > Dart' 카테고리의 다른 글
Dart 리스트 사용법. 생성부터 추가, 제거, 정렬까지 완벽 가이드 - Dart 기초 #13 (0) | 2024.06.17 |
---|---|
Dart에서 믹스인과 익스텐션 사용법: 다중 상속과의 차이점 - Dart 기초 #12 (0) | 2024.06.14 |
Dart 상속과 다형성: 예제 코드로 배우는 객체 지향 프로그래밍 - Dart 기초 #10 (0) | 2024.06.12 |
Dart 객체지향 프로그래밍: 생성자와 소멸자 개념과 예제 - Dart 기초 #9 (0) | 2024.06.11 |
Dart 객체지향 프로그래밍: 클래스와 객체 이해하기 - Dart 기초 #8 (0) | 2024.06.10 |