구현 vs 확장
Coddy Dart 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨 — 110개 중 47번째.
이제 extends와 implements를 모두 이해하셨으니, 각각을 언제 사용해야 하는지 명확히 알아봅시다.
동작을 상속받으려면 extends를 사용하세요. 서브클래스는 부모의 모든 코드를 그대로 물려받으며, 그 위에 기능을 추가할 수 있습니다:
class Animal {
void breathe() {
print('Breathing...');
}
}
class Dog extends Animal {
void bark() {
print('Woof!');
}
}
void main() {
var dog = Dog();
dog.breathe(); // 상속됨 - 자동으로 작동함
dog.bark();
}코드를 상속받지 않고 구조를 보장하고 싶을 때는 implements를 사용하세요. 모든 메서드를 직접 작성해야 합니다:
class Robot implements Animal {
@override
void breathe() {
print('Ventilating circuits...'); // 완전히 커스텀된 구현
}
}핵심적인 차이점: extends는 "나는 이것의 한 종류이다"라고 말하는 반면, implements는 "나는 이것이 하는 일을 할 수 있다"라고 말합니다. Dog는 Animal의 일종이며 같은 방식으로 숨을 쉽니다. Robot은 동물이 아니지만, 자체적인 로직으로 동일한 계약을 이행할 수 있습니다.
기억하세요: 하나의 클래스만 상속할 수 있지만, 여러 개의 인터페이스는 구현할 수 있습니다. 진정한 상속 관계를 위해서는 extends를 선택하고, 유연성이 필요하거나 구현 세부 사항을 공유하지 않고 계약을 강제하고 싶을 때는 implements를 선택하세요.
챌린지
쉬움extends와 implements를 언제 사용해야 하는지 보여주는 작업자 시스템을 구축해 보겠습니다. 기본 작업자 클래스를 만든 다음 두 가지 접근 방식을 모두 보여줄 것입니다. 하나는 진정으로 작업자"이며" 동작을 상속받는 클래스이고, 다른 하나는 단순히 작업자가 하는 일을 "할 수 있지만" 완전히 사용자 정의된 로직을 가진 클래스입니다.
코드를 두 개의 파일로 구성합니다:
worker.dart: 여기에 작업자 계층 구조를 정의합니다:String name속성과 생성자를 가진Worker클래스.[name] is working...을 출력하는work()메서드와[name] takes a coffee break를 출력하는takeBreak()메서드를 포함합니다.Worker를 extends하는OfficeWorker클래스.String department속성을 추가합니다.work()를 오버라이드하여[name] is typing reports in [department]를 출력하도록 하되, 상속받은takeBreak()동작은 그대로 유지합니다.Worker를 implements하는RobotWorker클래스.String model속성을 추가합니다. 로봇은 실제 작업자는 아니지만 작업자가 하는 일을 할 수 있으므로, 완전히 사용자 정의된 구현을 제공합니다:work()는Robot [model] is assembling parts를 출력해야 하고,takeBreak()는Robot [model] is recharging을 출력해야 합니다.
main.dart: 작업자 파일을 임포트하고 두 가지 접근 방식을 모두 시연합니다:'Marketing'부서에'Alice'라는 이름의OfficeWorker를 생성합니다.- 모델명이
'RX-7'인RobotWorker를 생성합니다. - 사무직 작업자(office worker)에 대해
work()를 호출한 다음takeBreak()를 호출합니다. - 빈 줄을 출력합니다.
- 로봇 작업자(robot worker)에 대해
work()를 호출한 다음takeBreak()를 호출합니다.
OfficeWorker는 Worker를 확장(extends)하기 때문에 takeBreak()를 자동으로 상속받는 방식(진정한 작업자 "임")을 확인해 보세요. 반면, RobotWorker는 인터페이스만 구현(implements)하기 때문에 모든 것에 대해 자체적인 구현을 제공해야 합니다. 즉, 작업자가 하는 일을 "할 수" 있지만, 로봇만의 방식으로 수행합니다.
예상 출력:
Alice is typing reports in Marketing
Alice takes a coffee break
Robot RX-7 is assembling parts
Robot RX-7 is recharging치트 시트
부모 클래스로부터 동작을 상속받으려면 extends를 사용하세요. 서브클래스는 자동으로 모든 부모 메서드를 가져오며 이를 오버라이드할 수 있습니다:
class Animal {
void breathe() {
print('Breathing...');
}
}
class Dog extends Animal {
void bark() {
print('Woof!');
}
}
void main() {
var dog = Dog();
dog.breathe(); // Inherited automatically
dog.bark();
}코드를 상속받지 않고 구조를 보장하려면 implements를 사용하세요. 모든 메서드에 대해 직접 구현을 제공해야 합니다:
class Robot implements Animal {
@override
void breathe() {
print('Ventilating circuits...');
}
}주요 차이점:
extends: "나는 이것의 한 종류이다" - 코드를 공유하는 진정한 상속implements: "나는 이것이 하는 일을 할 수 있다" - 커스텀 로직으로 계약을 강제함- 하나의 클래스만 확장(extend)할 수 있지만, 여러 인터페이스를 구현(implement)할 수 있습니다.
동작을 상속받아야 하는 진정한 부모-자식 관계에는 extends를 선택하세요. 유연성이 필요하거나 구현을 공유하지 않고 계약을 강제하고 싶을 때는 implements를 선택하세요.
직접 해보기
import 'worker.dart';
void main() {
// TODO: 'Marketing' 부서의 'Alice'라는 이름의 OfficeWorker를 생성하세요.
// TODO: 모델명이 'RX-7'인 RobotWorker를 생성하세요.
// TODO: office worker에 대해 work()를 호출한 다음 takeBreak()를 호출하세요.
// TODO: 빈 줄을 출력하세요.
// TODO: robot worker에 대해 work()를 호출한 다음 takeBreak()를 호출하세요.
}
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.