추상 메서드
Coddy Dart 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨 — 110개 중 44번째.
추상 메서드(abstract method)는 본문이 없는 추상 클래스(abstract class) 내부에 선언된 메서드입니다. 이는 메서드 시그니처를 정의하지만 구현은 각 하위 클래스(subclass)에 맡깁니다. 추상 클래스를 상속받는 모든 클래스는 모든 추상 메서드를 반드시 오버라이드(override)해야 하며, 그렇지 않으면 해당 클래스도 추상 클래스가 됩니다.
abstract class Animal {
// 추상 메서드 - 본문이 없으며, 하위 클래스에서 반드시 구현해야 함
String makeSound();
// 구체적인 메서드 - 본문이 있으며, 모든 하위 클래스에서 공유됨
void breathe() {
print('Breathing...');
}
}
class Dog extends Animal {
@override
String makeSound() {
return 'Woof!'; // 반드시 구현을 제공해야 함
}
}
class Cat extends Animal {
@override
String makeSound() {
return 'Meow!'; // 다른 구현, 동일한 시그니처
}
}만약 서브클래스가 추상 메서드를 구현하는 것을 잊는다면, Dart는 컴파일 에러를 발생시킵니다. 이것이 바로 핵심입니다 - 추상 메서드는 계약을 강제합니다. 모든 서브클래스는 해당 메서드를 갖는 것이 보장되므로, 추상 타입의 어떤 인스턴스에서도 안전하게 그 메서드를 호출할 수 있습니다.
// 추상 타입을 변수 타입으로 사용할 수 있습니다
Animal a = Dog();
print(a.makeSound()); // 멍멍!
Animal b = Cat();
print(b.makeSound()); // 야옹!추상 메서드는 추상 클래스 내의 구체 메서드(concrete methods)와 다릅니다. 구체 메서드는 본문(body)을 가지며 있는 그대로 상속됩니다. 반면 추상 메서드는 본문이 없으며 반드시 오버라이드(재정의)되어야 합니다.
동일한 추상 클래스 내에서 두 가지를 혼합하여 일부 동작은 공유하면서, 다른 동작에 대해서는 서브클래스가 직접 정의하도록 강제할 수 있습니다.
| 기능 | 추상 메서드 | 구체 메서드 |
|---|---|---|
| 본문(body) 유무 | 아니요 | 예 |
| 오버라이딩 필수 여부 | 예 | 아니요 |
| 목적 | 계약 강제 | 동작 공유 |
| 선언 위치 | 추상 클래스 전용 | 모든 클래스 |
챌린지
쉬움추상 메서드가 실제로 어떻게 작동하는지 보여주는 도형 계산기를 만들어 보겠습니다. 각 도형이 서로 다르게 구현해야 하는 추상 메서드를 가진 추상 클래스를 정의한 다음, 공통 인터페이스를 통해 해당 도형들을 사용해 볼 것입니다.
코드는 다음 네 개의 파일로 구성됩니다:
shape.dart:final필드인color(String)와 이를 초기화하는 생성자를 가진 추상 클래스Shape를 정의합니다. 두 개의 추상 메서드double area()와double perimeter()를 선언하세요. 또한A [color] shape with area: [area] and perimeter: [perimeter]를 출력하는 구체 메서드describe()를 추가하세요.area()와perimeter()는 추상 메서드이므로 각 서브클래스에서 자체적인 계산 방식을 제공하겠지만,describe()는 오버라이드 없이 모든 서브클래스에서 작동합니다.circle.dart:Shape를 상속받는Circle클래스를 생성합니다.final필드인radius(double)를 가집니다. 생성자는color와radius를 인자로 받아color를super로 전달합니다.area()는3.14 * radius * radius를 반환하도록 구현하고,perimeter()는2 * 3.14 * radius를 반환하도록 구현하세요.rectangle.dart:Shape를 상속받는Rectangle클래스를 생성합니다.final필드인width와height(둘 다 double)를 가집니다. 생성자는color,width,height를 인자로 받아color를super로 전달합니다.area()는width * height를 반환하도록 구현하고,perimeter()는2 * (width + height)를 반환하도록 구현하세요.main.dart: 모든 파일을 임포트합니다. 색상이'red'이고 반지름이5.0인Circle과, 색상이'blue'이고 너비가4.0, 높이가6.0인Rectangle을 생성합니다. 각 도형에 대해describe()를 호출하세요. 그런 다음 두 도형을 모두 포함하는List<Shape>를 생성하고, 리스트를 반복문으로 돌면서 각 도형의Area: [area]를 출력하세요.
예상 출력 결과:
A red shape with area: 78.5 and perimeter: 31.400000000000002
A blue shape with area: 24.0 and perimeter: 20.0
Area: 78.5
Area: 24.0치트 시트
추상 메서드는 본문 없이 추상 클래스에서 선언된 메서드입니다. 하위 클래스는 자체적인 구현을 제공하기 위해 이를 반드시 오버라이드해야 합니다.
abstract class Animal {
// 추상 메서드 - 본문 없음
String makeSound();
// 구체 메서드 - 본문 있음
void breathe() {
print('Breathing...');
}
}하위 클래스는 모든 추상 메서드를 구현해야 합니다:
class Dog extends Animal {
@override
String makeSound() {
return 'Woof!';
}
}
class Cat extends Animal {
@override
String makeSound() {
return 'Meow!';
}
}추상 타입을 변수 타입으로 사용할 수 있습니다:
Animal a = Dog();
print(a.makeSound()); // Woof!
Animal b = Cat();
print(b.makeSound()); // Meow!| 특징 | 추상 메서드 | 구체 메서드 |
|---|---|---|
| 본문 유무 | 아니요 | 예 |
| 오버라이드 필수 여부 | 예 | 아니요 |
| 목적 | 계약 강제 | 동작 공유 |
| 위치 | 추상 클래스 전용 | 모든 클래스 |
직접 해보기
import 'shape.dart';
import 'circle.dart';
import 'rectangle.dart';
void main() {
// TODO: color가 'red'이고 radius가 5.0인 Circle을 생성하세요.
// TODO: color가 'blue'이고 width가 4.0, height가 6.0인 Rectangle을 생성하세요.
// TODO: circle에 대해 describe()를 호출하세요.
// TODO: rectangle에 대해 describe()를 호출하세요.
// TODO: 두 도형을 포함하는 List<Shape>를 생성하세요.
// TODO: 리스트를 반복문으로 돌며 각 도형에 대해 "Area: [area]"를 출력하세요.
}
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.