🏗️

Dartクラス&OOP

コンストラクタ5種、継承、インターフェース、Mixin、ファクトリパターン

Dartは完全なオブジェクト指向言語ですべてがオブジェクトです。基本、名前付き、初期化リスト、const、factoryの5種コンストラクタを提供し、extendsで継承、implementsでインターフェース、withでMixinを実現します。ファクトリコンストラクタはfromJson直列化、シングルトン、条件別サブクラス返却など実戦で頻繁に使います。

1. 클래스 기본 구조

Dart에서 모든 것은 객체이며, 모든 객체는 클래스의 인스턴스입니다. 클래스는 필드, 생성자, 메서드, getter/setter로 구성됩니다.

class Person { String name; int age; Person(this.name, this.age); void introduce() { print('안녕하세요, 저는 $name이고 $age살입니다.'); } bool get isAdult => age >= 18; set setAge(int newAge) { if (newAge >= 0) { age = newAge; } }}

2. Private 멤버 (_ 언더스코어)

언더스코어(_)로 시작하는 멤버는 라이브러리(파일) 수준 private입니다. public getter로 안전하게 노출합니다.

class Person { String name; int _age; Person(this.name, this._age); int get age => _age; void _privateMethod() { print('내부에서만 호출 가능'); } void publicMethod() { _privateMethod(); }}

3. 생성자 5종

3-1. 기본 생성자 (shorthand)

this.name으로 파라미터를 자동 할당

Person(this.name, this.age);

3-2. 이름 있는 생성자 (Named Constructor)

같은 클래스에 여러 생성자를 만들 수 있습니다.

Person.guest() { name = '손님'; age = 0; } Person.child(this.name) { age = 10; } Person.adult(this.name) { age = 18; } // 사용: Person.guest(), Person.child('아이'), Person.adult('성인')

3-3. 초기화 리스트 (Initializer List)

생성자 본문 실행 전 : 뒤에서 필드 초기화. final 필드에 유용.

Person(this.name, this.age) : birthDate = DateTime.now().subtract(Duration(days: 365 * age)); Person.custom(String userName, int userAge) : name = userName.toUpperCase(), age = userAge > 0 ? userAge : 0, birthDate = DateTime.now().subtract(Duration(days: 365 * userAge));

3-4. 상수 생성자 (Const Constructor)

불변 객체. 동일 값의 const 인스턴스는 같은 객체를 참조.

class ImmutablePoint { final int x; final int y; const ImmutablePoint(this.x, this.y); } var p1 = const ImmutablePoint(1, 2); var p2 = const ImmutablePoint(1, 2); print(identical(p1, p2)); // true

3-5. 리다이렉팅 생성자 (Redirecting)

: this(...)로 다른 생성자에 위임.

Person.adult(String name) : this(name, 18); Person.child(String name) : this(name, 10); Person.fromJson(Map<String, dynamic> json) : this(json['name'] as String, json['age'] as int);

4. 생성자 비교 테이블

종류문법용도
기본Person(this.name)자동 초기화
이름 있는Person.guest()여러 초기화
초기화 리스트: birthDate = ...파생값/final
상수const Person()불변 객체
리다이렉팅: this(name, 18)생성자 위임
팩토리factory Logger(name)캐싱/싱글톤

5. 팩토리 생성자 (Factory Constructor)

5-1. 캐싱 — Logger

class Logger { final String name; static final Map<String, Logger> _cache = {}; Logger._internal(this.name); factory Logger(String name) { return _cache.putIfAbsent(name, () => Logger._internal(name)); } } final l1 = Logger('UI'); final l2 = Logger('UI'); print(identical(l1, l2)); // true

5-2. 하위 클래스 반환 — Shape

abstract class Shape { factory Shape(String type) { switch (type) { case 'circle': return Circle(10); case 'rectangle': return Rectangle(10, 20); default: throw ArgumentError('지원하지 않는 도형: $type'); } } double get area; } class Circle implements Shape { final double radius; Circle(this.radius); @override double get area => 3.14 * radius * radius; } class Rectangle implements Shape { final double width, height; Rectangle(this.width, this.height); @override double get area => width * height; }

5-3. fromJson — User

Flutter API 응답 모델에 필수 패턴.

class User { final String name; final int age; final String email; User(this.name, this.age, this.email); factory User.fromJson(Map<String, dynamic> json) { return User(json['name'] as String, json['age'] as int, json['email'] as String); } Map<String, dynamic> toJson() => {'name': name, 'age': age, 'email': email}; }

6. 정적 멤버 (Static)

class MathUtils { static const double PI = 3.14159; static int calculationCount = 0; static double square(double num) { calculationCount++; return num * num; } } print(MathUtils.PI); print(MathUtils.square(5)); // 25.0

7. 추상 클래스

abstract class Animal { String name; Animal(this.name); void makeSound(); void sleep() { print('$name is sleeping'); } } class Dog extends Animal { Dog(String name) : super(name); @override void makeSound() { print('$name says Woof!'); } }

8. 인터페이스 (implements)

Dart는 별도 interface 키워드 없이, 모든 클래스가 인터페이스. implements 시 모든 멤버 재정의 필수.

class Car implements Vehicle { @override void move() { print('Car is driving'); } @override void stop() { print('Car stopped'); } } Vehicle vehicle = Car(); vehicle.move(); // 다형성

9. 상속 (extends)

class Student extends Person { String school; Student(String name, int age, this.school) : super(name, age); @override void introduce() { super.introduce(); print('저는 $school에 다니고 있습니다.'); } }

10. Mixin (with)

깊은 상속 없이 기능 재사용. with로 다중 Mixin 적용.

mixin Swimming { void swim() { print('수영 중'); } } mixin Flying { void fly() { print('비행 중'); } } class Duck extends Animal with Swimming, Flying { Duck(String name) : super(name); } final duck = Duck('오리'); duck.swim(); duck.fly();

mixin CanFly on Bird — 특정 클래스에서만 사용 가능하도록 제한

11. extends vs implements vs with

키워드다중구현 상속용도
extends단일Ois-a 상속
implements다중X인터페이스
with다중O기능 조합

12. Named Parameters

class Person { String name; int age; String? address; Person({required this.name, required this.age, this.address}); } final p = Person(name: '홍길동', age: 30);

13. 연산자 오버로딩

class Vector { final double x, y; const Vector(this.x, this.y); Vector operator +(Vector o) => Vector(x + o.x, y + o.y); @override bool operator ==(Object o) { if (identical(this, o)) return true; return o is Vector && o.x == x && o.y == y; } @override int get hashCode => x.hashCode ^ y.hashCode; } print(Vector(1,2) + Vector(3,4)); // Vector(4,6) print(Vector(1,2) == Vector(1,2)); // true

핵심 정리

  • Private — _ 접두사, getter로 노출
  • 생성자 5종 — 기본/이름/초기화리스트/상수/리다이렉팅
  • 팩토리 — 캐싱, 하위클래스 반환, fromJson
  • 상속 — extends/implements/with
  • 연산자 오버로딩 — operator +/==

実装ステップ

1

基本コンストラクタ — Person(this.name, this.age)でフィールド自動初期化の簡潔な文法

2

ファクトリコンストラクタ — factoryキーワードでキャッシュ/シングルトン/fromJson/条件別サブクラス返却

3

Mixin — withキーワードで多重機能組合せ、class Duck extends Animal with Swimming, Flying

4

abstract class — 抽象メソッドを定義しサブクラスで実装強制、インターフェース役割も兼ねる

メリット

  • Mixinで多重継承の利点を安全に活用可能
  • ファクトリコンストラクタで柔軟なオブジェクト生成パターン実現

デメリット

  • コンストラクタ5種類で初心者には選択が難しい可能性

ユースケース

APIレスポンスモデルでfactory fromJson()パターン使用 FlutterウィジェットでMixinによる共通機能(アニメーション、ジェスチャー等)の再利用