중급

객체지향

상속, 구현, 캡슐화, 다형성을 Flutter 코드에서 어떻게 읽고 쓰는지 정리합니다.

개념 먼저 보기

객체지향의 기본 개념부터 잡기

객체지향 문서는 먼저 용어의 뜻을 잡고, 그 다음 Flutter 코드에서 어디에 쓰이는지 연결해서 읽는 것이 좋습니다.

아래 항목들은 이 문서에서 다루는 내용을 작은 단위로 나눈 것입니다. 각 항목을 읽은 뒤 예제를 보면 코드가 훨씬 덜 추상적으로 느껴집니다.

종류별로 하나씩

객체지향에서 나눠 볼 핵심 요소

핵심 개념

캡슐화는 내부 구현을 숨기고 필요한 인터페이스만 드러내는 방식입니다.

언제 쓰나: 상속은 기존 클래스의 동작을 확장합니다.

Flutter에서: 다형성은 같은 인터페이스를 다른 구현으로 바꿔 사용할 수 있게 합니다.

// 객체지향 예제입니다.
// 먼저 코드의 큰 흐름을 보고, 주석을 따라 각 줄의 역할을 확인하세요.
abstract class LessonRepository {
  Future<List<Lesson>> fetchLessons();
}

class ApiLessonRepository implements LessonRepository {
  @override
  Future<List<Lesson>> fetchLessons() async => [];
}

Flutter에서의 활용

StatelessWidget과 StatefulWidget을 상속해 위젯을 만듭니다.

언제 쓰나: abstract class로 저장소나 서비스의 계약을 정의할 수 있습니다.

Flutter에서: 테스트에서는 추상화된 인터페이스를 가짜 구현으로 바꿔 검증합니다.

// 객체지향 예제입니다.
// 먼저 코드의 큰 흐름을 보고, 주석을 따라 각 줄의 역할을 확인하세요.
abstract class LessonRepository {
  Future<List<Lesson>> fetchLessons();
}

class ApiLessonRepository implements LessonRepository {
  @override
  Future<List<Lesson>> fetchLessons() async => [];
}

부연 설명

핵심 개념

  • 캡슐화는 내부 구현을 숨기고 필요한 인터페이스만 드러내는 방식입니다.
  • 상속은 기존 클래스의 동작을 확장합니다.
  • 다형성은 같은 인터페이스를 다른 구현으로 바꿔 사용할 수 있게 합니다.

부연 설명

Flutter에서의 활용

  • StatelessWidget과 StatefulWidget을 상속해 위젯을 만듭니다.
  • abstract class로 저장소나 서비스의 계약을 정의할 수 있습니다.
  • 테스트에서는 추상화된 인터페이스를 가짜 구현으로 바꿔 검증합니다.

깊게 이해하기

객체지향은 단순히 class 문법을 쓰는 것이 아니라 책임을 적절한 객체에 배치하는 사고방식입니다. 데이터와 동작이 함께 있어야 자연스러운지, 아니면 별도 서비스가 더 적합한지 판단해야 합니다.

Flutter에서 객체지향은 위젯 상속뿐 아니라 Repository 인터페이스, 테스트 대역, 도메인 모델 설계에서 계속 등장합니다.

상세 예제

추상 저장소와 구현체를 분리해 테스트 가능한 구조를 만드는 예제입니다.

abstract class LessonRepository {
  Future<List<Lesson>> findAll();
}

class RemoteLessonRepository implements LessonRepository {
  RemoteLessonRepository(this.client);

  final ApiClient client;

  @override
  Future<List<Lesson>> findAll() async {
    final json = await client.get('/lessons');
    return json.map(Lesson.fromJson).toList();
  }
}

class FakeLessonRepository implements LessonRepository {
  @override
  Future<List<Lesson>> findAll() async => [
        const Lesson(id: 'test', title: '테스트 강의'),
      ];
}

실무에서 주의할 점

  • 상속보다 인터페이스와 조합이 더 단순한 경우가 많습니다.
  • 추상화는 테스트나 교체 가능성처럼 실제 이유가 있을 때 추가하세요.
  • 객체가 너무 많은 책임을 가지면 작은 클래스로 나누세요.

실습 체크리스트

abstract class 작성extends와 implements 차이 설명테스트 가능한 인터페이스 설계