객체지향 프로그래밍(OOP)에서 추상 클래스는 특정 동작이나 속성을 강제하기 위한 강력한 도구입니다.
Dart에서도 추상 클래스는 상속을 통해 일반화된 동작을 구체적인 구현으로 확장할 수 있는 기회를 제공합니다.
이번 포스팅에서는 Dart의 추상 클래스에 대해 알아보고,
왜 추상 클래스가 필요한지,
그리고 실전 코드에서 어떻게 활용되는지를 살펴보겠습니다.
1. 추상 클래스란?
추상 클래스(Abstract Class)는 완전한 구현을 제공하지 않는 클래스입니다.
특정 동작을 서브 클래스가 반드시 구현하도록 강제할 수 있습니다.
- 인스턴스화 불가: 추상 클래스는 직접 객체를 생성할 수 없습니다.
- 추상 메서드: 메서드 본체가 없는, 반드시 구현해야 하는 메서드를 포함할 수 있습니다.
- 상속 필수: 추상 클래스는 다른 클래스가 이를 상속하고 구체적인 동작을 정의하도록 설계됩니다.
2. 추상 클래스 없이 설계할 때 발생하는 문제
아래는 유아용 동물 소리 프로그램의 예시입니다.
✔ 우리 회사는 유아용 동물 소리 프로그램을 만듭니다. 그리고 팀장님께서 물고기 소리 나는 프로그램을 만들어 달라 요청을 했다면 어떻게 될까요?
(Dog 클래스와 Cat 클래스는 이미 설계되어 있음)
// 팀장이 물고기 소리 나는 프로그램을 만들어 달라 요청을 했다면?
class Dog {
void performAction() {
print('멍멍 배고파');
}
}
class Cat {
void performAction() {
print('야옹 배고파');
}
}
//신입이 작성했다고 가정
class Fish {
void hungry() {
print('뻐끔뻐끔 배고파');
}
}
void main() {
Dog d = Dog();
Cat c = Cat();
Fish f = Fish();
f.hungry();
// f.performAction(); 동적인 코드로 돌렸다면 오류 발생(Fish 클래스에는 performAction이 없음)
}
3. 추상 클래스를 활용한 해결
💡 이때 추상 클래스를 활용하면 손쉽게 해결할 수 있습니다.
Animal 추상 클래스를 만들어 모든 동물이 공통적으로 가져야 할 동작(performAction)을 정의합니다.
abstract class Animal {
void performAction();
}
class Dog implements Animal {
@override
void performAction() {
print('멍멍 배고파');
}
}
class Cat implements Animal {
@override
void performAction() {
print('야옹 배고파');
}
}
class Fish implements Animal {
@override
void performAction() {
print('뻐끔뻐끔 배고파');
}
}
동적 바인딩을 활용한 설계
이제 동적 바인딩을 통해 다양한 동물 객체를 동일한 방식으로 처리할 수 있습니다.
- 모든 동물 클래스는 performAction을 반드시 구현해야 하므로 일관성을 유지
- start 함수는 동적 바인딩을 통해 다양한 동물 객체를 처리
void start(Animal a) {
a.performAction(); // 동적으로 호출
}
void main() {
start(Dog());
start(Cat());
start(Fish());
}
4. 동적 바인딩이란?
동적 바인딩(Dynamic Binding)은 프로그램 실행 중에 호출할 메서드를 결정하는 방식입니다.
위 코드에서 start 함수는 Dog, Cat, Fish 객체의 구체적인 performAction 구현을 실행 시점에 동적으로 호출합니다. 이를 통해 유연하고 확장 가능한 설계를 구현할 수 있습니다.
abstract class Animal {
void performAction();
}
// 추상 클래스를 구현할 때 implements 를 사용
class Dog implements Animal {
@override
void performAction() {
print('멍멍 배고파');
}
}
class Cat implements Animal {
@override
void performAction() {
print('야옹 배고파');
}
}
class Fish implements Animal {
@override
void performAction() {
print('뻐끔뻐끔 배고파');
}
}
// 한 단계 더 나아가 보자~ 실력 쌓기
// 동적 바인딩이란 뭘까?
void start(Animal a) {
// performAction() 메서드가 동작하게 만들고 싶다.
// 단, 강아지든 고양이든 물고기든 동적으로 들어오더라도 performAction이 호출되도록 설계
a.performAction();
}
void main() {
start(Dog());
start(Cat());
start(Fish());
}
4 - 2. 추상 클래스 사용 연습
추상 클래스와 동적 바인딩을 활용한 다형성 구현하기
Shape라는 추상 클래스를 정의하고, 이를 상속받은 Circle과 Rectangle 클래스가 있습니다. calculateArea 함수를 통해 동적 바인딩을 활용하여 다양한 도형의 면적을 계산할 수 있도록 구현하세요
//추상 클래스
abstract class Shape {
// 메서드의 바디(구현부)가 없다면 추상 메서드
double getArea();
}
// 문제가 뭐지? 면적을 구하는 일을 해결해야 한다.
class Circle implements Shape {
final double radius;
// 생성자는 가능한 축약형으로 만들자 - 우리들의 규칙
Circle(this.radius);
// 면적을 구하는 행위
@override
double getArea() {
return 3.14 * radius * radius;
}
}
class Rectangle implements Shape {
final double width;
final double height;
Rectangle(this.width, this.height);
// 면적을 구하는 행위를 해야 한다
@override
double getArea() {
return width * height;
}
}
// 동적 바인딩을 활용한 함수를 설계해 보자
// 전역 함수 설계
void calculateArea(Shape s) {
// 전달된 도형의 면적을 출력하시오.
print(s.getArea());
}
void main() {
Shape myCir = Circle(5.3);
Shape myRec = Rectangle(4.0, 3.5);
calculateArea(myCir);
calculateArea(myRec);
}
✔ Dart에서 추상 클래스를 사용해야 할 때
공통된 속성과 메서드가 필요한 경우
반드시 구현해야 할 동작을 서브 클래스에 강제하려는 경우
추상 클래스는 객체 지향 프로그래밍(OOP)에서 설계의 강력한 도구로,
클래스 간의 일관성과 재사용성을 확보하는 데 큰 도움을 줍니다.
Dart에서 추상 클래스는 공통된 동작을 강제하거나, 동적 바인딩을 활용한 유연한 설계를 가능하게 합니다.
추상 클래스를 올바르게 활용하면 코드의 가독성과 유지보수성이 향상될 뿐만 아니라,
협업 과정에서도 명확한 설계를 제공할 수 있습니다.
❓ dart에서 클래스를 설계하는 방법이 궁금하다면?
[DART] 클래스와 인스턴스
프로그래밍에서 클래스와 인스턴스는 객체 지향 프로그래밍(OOP)의 가장 기본적인 개념입니다.이번 포스팅에서는 클래스와 인스턴스의 정의, 객체 지향 프로그래밍의 개념, 그리고 Dart에서 이를
dev-yeonwha.tistory.com
아래의 문헌을 참고하여 작성된 포스팅입니다.
최주호, 김근호, 이지원(공저) 『만들면서 배우는 플러터 앱 프로그래밍』, 앤써북, 2023.
'Flutter > Dart' 카테고리의 다른 글
[DART] 비동기 프로그래밍(Future) 알아보기 (0) | 2025.01.15 |
---|---|
[DART] OOP 연관관계와 Mixin (1) | 2025.01.07 |
[DART] 상속(Inheritance)이란 무엇인가요? (0) | 2025.01.06 |
[DART] Sound Null Safety in dart (0) | 2025.01.06 |
[DART] 클래스와 인스턴스 (2) | 2025.01.03 |