Menu
Coddy logo textTech

제네릭 클래스

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

Dart의 List<String>과 같은 내장 컬렉션이 타입 매개변수를 어떻게 사용하는지 살펴보았습니다. 이제 여러분이 지정하는 어떤 타입과도 작동하는 여러분만의 제네릭 클래스를 직접 만들어 볼 차례입니다.

제네릭 클래스는 인스턴스를 생성할 때 제공될 실제 타입을 위한 플레이스홀더로 타입 매개변수(일반적으로 T)를 사용합니다:

class Box<T> {
  T content;
  
  Box(this.content);
  
  T getContent() => content;
}

void main() {
  var stringBox = Box<String>('Hello');
  var intBox = Box<int>(42);
  
  print(stringBox.getContent());  // Hello
  print(intBox.getContent());     // 42
}

T는 타입 변수 역할을 합니다. Box<String>을 생성할 때, 클래스 내의 모든 TString이 됩니다. 이는 각 타입에 대해 별도의 클래스를 작성하지 않고도 타입 안정성을 제공합니다.

클래스가 둘 이상의 타입을 처리해야 할 때 여러 개의 타입 매개변수를 사용할 수 있습니다:

class Pair<K, V> {
  K first;
  V second;
  
  Pair(this.first, this.second);
}

void main() {
  var pair = Pair<String, int>('age', 25);
  print('${pair.first}: ${pair.second}');  // age: 25
}

제네릭 클래스는 재사용 가능하고 타입 안전한 코드의 기초입니다. 서로 다른 타입에 대해 로직을 중복 작성하거나 dynamic을 사용하여 타입 정보를 잃는 대신, 제네릭을 사용하면 컴파일러가 여전히 검증할 수 있는 유연한 코드를 작성할 수 있습니다.

challenge icon

챌린지

쉬움

다양한 유형의 아이템을 위한 유연한 컨테이너를 만들기 위해 제네릭 클래스를 사용하는 선물 포장 시스템을 구축해 보겠습니다. 어떤 유형의 내용물도 포장할 수 있는 제네릭 Wrapper 클래스와, 선물과 카드 메시지를 쌍으로 묶기 위해 두 개의 타입 매개변수를 가진 GiftBox 클래스를 만들 것입니다.

코드를 두 개의 파일로 구성합니다:

  • wrapper.dart: 여기에 제네릭 클래스들을 정의하세요:
    • T content 속성과 생성자를 가진 제네릭 클래스 Wrapper<T>. 내용물을 반환하는 unwrap() 메서드와, Wrapped: [content]를 출력하는 describe() 메서드를 포함하세요.
    • 두 개의 속성 G giftC card를 가진 제네릭 클래스 GiftBox<G, C>. 생성자와 함께, 첫 번째 줄에 Gift: [gift]를 출력하고 다음 줄에 Card: [card]를 출력하는 open() 메서드를 포함하세요.
  • main.dart: wrapper 파일을 임포트하고 다양한 타입을 사용하여 제네릭 클래스들을 시연하세요:
    • 'Chocolate'을 포함하는 Wrapper<String>을 생성하고 describe()를 호출하세요.
    • 42를 포함하는 Wrapper<int>를 생성하고 describe()를 호출하세요.
    • 3.14를 포함하는 Wrapper<double>을 생성하고 describe()를 호출하세요.
    • 빈 줄을 출력하세요.
    • 선물 'Teddy Bear'와 카드 'Happy Birthday!'를 가진 GiftBox<String, String>을 생성한 후 open()을 호출하세요.
    • 빈 줄을 출력하세요.
    • 선물 100(기프트 카드 금액을 나타냄)과 카드 'Congratulations!'를 가진 GiftBox<int, String>을 생성한 후 open()을 호출하세요.

동일한 Wrapper 클래스가 문자열, 정수, 실수와 어떻게 원활하게 작동하는지 확인해 보세요. GiftBox 클래스는 두 개의 타입 매개변수를 사용하여 서로 다른 타입을 쌍으로 묶는 방법을 보여줍니다. 선물은 어떤 타입이든 될 수 있는 반면 카드 메시지는 문자열로 유지됩니다.

예상 출력:

Wrapped: Chocolate
Wrapped: 42
Wrapped: 3.14

Gift: Teddy Bear
Card: Happy Birthday!

Gift: 100
Card: Congratulations!

치트 시트

제네릭 클래스는 인스턴스를 생성할 때 지정되는 실제 타입에 대한 플레이스홀더로 타입 매개변수(예: T)를 사용합니다:

class Box<T> {
  T content;
  
  Box(this.content);
  
  T getContent() => content;
}

void main() {
  var stringBox = Box<String>('Hello');
  var intBox = Box<int>(42);
  
  print(stringBox.getContent());  // Hello
  print(intBox.getContent());     // 42
}

Box<String>을 생성하면 클래스 내의 모든 TString이 되어, 각 타입별로 별도의 클래스를 만들지 않고도 타입 안전성을 제공합니다.

둘 이상의 타입을 다룰 때는 여러 개의 타입 매개변수를 사용하세요:

class Pair<K, V> {
  K first;
  V second;
  
  Pair(this.first, this.second);
}

void main() {
  var pair = Pair<String, int>('age', 25);
  print('${pair.first}: ${pair.second}');  // age: 25
}

직접 해보기

import 'wrapper.dart';

void main() {
  // TODO: 'Chocolate'를 포함하는 Wrapper<String>을 생성하고 describe()를 호출하세요
  
  // TODO: 42를 포함하는 Wrapper<int>를 생성하고 describe()를 호출하세요
  
  // TODO: 3.14를 포함하는 Wrapper<double>을 생성하고 describe()를 호출하세요
  
  // TODO: 빈 줄을 출력하세요
  
  // TODO: gift가 'Teddy Bear'인 GiftBox<String, String>을 생성하고 
  // card가 'Happy Birthday!'인 것을 확인한 후 open()을 호출하세요
  
  // TODO: 빈 줄을 출력하세요
  
  // TODO: gift가 100인 GiftBox<int, String>을 생성하고 
  // card가 'Congratulations!'인 것을 확인한 후 open()을 호출하세요
}
quiz icon실력 점검

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

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