Menu
CoddyTech

합성 vs 상속

Coddy Dart 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨. 110개 중 82번째.

상속은 "is-a" 관계를 만든다는 것을 배웠습니다. 즉, Dog는 Animal입니다. 하지만 또 다른 강력한 접근 방식인 컴포지션은 "has-a" 관계를 만듭니다. 동작을 상속하는 대신, 클래스는 다른 클래스의 인스턴스를 포함하고 작업을 그 인스턴스에 위임합니다.

Car 클래스를 생각해 보세요. 상속을 사용하면 Engine 클래스를 확장하려고 할 수 있지만, 자동차는 엔진이 아니라 엔진을 가지고 있습니다:

class Engine {
  void start() => print('Engine started');
}

class Car {
  final Engine _engine = Engine();  // 컴포지션: Car는 Engine을 가지고 있음
  
  void start() {
    _engine.start();  // 엔진에 위임
    print('Car is ready to drive');
  }
}

void main() {
  var car = Car();
  car.start();
}

컴포지션의 핵심 장점은 유연성입니다. 상속을 사용하면 단일 부모 클래스에 묶이게 됩니다. 컴포지션을 사용하면 여러 구성 요소를 결합하고 런타임에 교체할 수도 있습니다.

class ElectricEngine {
  void start() => print('Electric motor humming');
}

class HybridCar {
  Engine? _gasEngine;
  ElectricEngine? _electricEngine;
  
  HybridCar({bool useElectric = false}) {
    if (useElectric) {
      _electricEngine = ElectricEngine();
    } else {
      _gasEngine = Engine();
    }
  }
}

일반적인 지침은 "상속보다 컴포지션을 우선하라"입니다. 실제로 "is-a" 관계가 있고 다형성이 필요할 때는 상속을 사용하세요. 긴밀한 결합 없이 동작을 재사용하고 싶거나 객체가 여러 출처의 기능을 필요로 할 때는 컴포지션을 사용하세요.

challenge icon

챌린지

쉬움

합성을 사용하여 컴퓨터 시스템을 만들어 봅시다! 컴퓨터가 부품을 상속하도록 만드는 대신, 별도의 구성 요소 클래스를 만들고 이들을 조합합니다. 컴퓨터는 CPU와 메모리를 가지고 있지, CPU나 메모리가 아니기 때문입니다.

코드를 세 개의 파일로 구성합니다.

  • components.dart: 컴퓨터 부품을 나타내는 두 개의 구성 요소 클래스를 만듭니다.
    • String brand와 double speedGHz를 가진 CPU 클래스를 만듭니다. 문자열을 반환하는 process() 메서드를 포함합니다: [brand] processing at [speedGHz]GHz
    • int sizeGB를 가진 Memory 클래스를 만듭니다. 문자열을 반환하는 load() 메서드를 포함합니다: Loading [sizeGB]GB of data
  • computer.dart: 합성을 사용해 구성 요소를 결합하는 Computer 클래스를 만듭니다. 컴퓨터는 다음과 같아야 합니다.
    • String name 필드를 가집니다.
    • CPU와 Memory 인스턴스를 포함합니다(합성 — 컴퓨터가 이 부품들을 가집니다).
    • 두 구성 요소를 내부적으로 생성하는 데 필요한 모든 값을 생성자를 통해 받습니다.
    • 두 구성 요소에 작업을 위임하고 세 줄을 출력하는 boot() 메서드를 가집니다. 컴퓨터 이름 뒤에 starting...을 출력하고, 이어서 CPU의 process 메서드 결과와 Memory의 load 메서드 결과를 출력합니다.
    • 시스템을 설명하는 문자열을 반환하는 specs() 메서드를 가집니다: [name]: [brand] [speedGHz]GHz, [sizeGB]GB RAM
  • main.dart: 파일을 가져오고 합성이 작동하는 모습을 보여 줍니다.
    • Intel CPU가 3.5 GHz로 작동하고 메모리가 16 GB인 Workstation이라는 Computer를 만듭니다.
    • boot() 메서드를 호출합니다.
    • specs()의 결과를 출력합니다.

Computer 클래스가 CPU나 Memory를 확장하지 않고, 이들을 포함하며 작업을 위임하는 점에 주목하세요. 이것이 합성이 만들어 내는 "has-a" 관계입니다!

예상 출력:

Workstation starting...
Intel processing at 3.5GHz
Loading 16GB of data
Workstation: Intel 3.5GHz, 16GB RAM

직접 해보기

import 'computer.dart';

void main() {
  // TODO: 이름이 "Workstation"인 Computer를 다음 사양으로 생성하세요:
  // - 3.5 GHz로 작동하는 Intel CPU
  // - 16 GB 메모리

  // TODO: boot() 메서드를 호출하세요

  // TODO: specs()의 결과를 출력하세요
}
quiz icon실력 점검

이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.

객체 지향 프로그래밍의 모든 레슨

직접 연습해 보세요: 온라인 Dart 컴파일러