클래스와 OOP
Dart의 클래스는 Java나 Kotlin과 비슷하지만, 믹스인(mixin), 확장 메서드(extension), sealed class 같은 현대적 기능이 추가됩니다. 실무에서 자주 쓰는 패턴 위주로 핵심만 압축합니다.
클래스 기본과 생성자
class Person {
final String name;
int age;
// 기본 생성자
Person(this.name, this.age);
// 명명된 생성자
Person.anonymous() : name = 'Unknown', age = 0;
// 팩토리 생성자 (캐싱, 서브타입 반환 가능)
factory Person.fromJson(Map<String, dynamic> json) {
return Person(json['name'] as String, json['age'] as int);
}
// 메서드
String greet() => 'Hi, I am $name.';
// toString 오버라이드
@override
String toString() => 'Person(name: $name, age: $age)';
}
void main() {
final p1 = Person('Alice', 30);
final p2 = Person.anonymous();
final p3 = Person.fromJson({'name': 'Bob', 'age': 25});
print(p1.greet()); // Hi, I am Alice.
}
초기화 리스트와 const 생성자
class Point {
final double x;
final double y;
// 초기화 리스트: 생성자 본문 실행 전 필드 초기화
const Point(this.x, this.y);
// const 생성자: 컴파일 타임 상수 인스턴스 생성 가능
static const origin = Point(0, 0);
double distanceTo(Point other) {
final dx = x - other.x;
final dy = y - other.y;
return (dx * dx + dy * dy); // sqrt 생략
}
@override
String toString() => 'Point($x, $y)';
}
const p = Point(3, 4);
상속
class Animal {
final String name;
Animal(this.name);
void speak() => print('$name makes a sound.');
}
class Dog extends Animal {
final String breed;
Dog(super.name, this.breed); // super 매개변수 (Dart 2.17+)
@override
void speak() => print('$name barks!');
void fetch() => print('$name fetches the ball.');
}
class GuideDog extends Dog {
GuideDog(super.name, super.breed);
@override
void speak() {
super.speak();
print('$name is a guide dog.');
}
}
추상 클래스와 인터페이스
// 추상 클래스: 공통 인터페이스 + 부분 구현
abstract class Shape {
double area(); // 추상 메서드
double perimeter();
// 구체 메서드
bool isLargerThan(Shape other) => area() > other.area();
}
class Circle extends Shape {
final double radius;
Circle(this.radius);
@override
double area() => 3.14159 * radius * radius;
@override
double perimeter() => 2 * 3.14159 * radius;
}
// Dart의 모든 클래스는 암묵적으로 인터페이스
// implements로 인터페이스처럼 사용
class MockShape implements Shape {
@override
double area() => 0;
@override
double perimeter() => 0;
@override
bool isLargerThan(Shape other) => false;
}
믹스인 (Mixin)
다중 상속 없이 여러 클래스의 기능을 조합합니다.
mixin Flyable {
void fly() => print('$runtimeType is flying!');
int get altitude => 1000;
}
mixin Swimmable {
void swim() => print('$runtimeType is swimming!');
}
class Bird with Flyable {}
class Duck extends Animal with Flyable, Swimmable {
Duck() : super('Duck');
}
void main() {
final duck = Duck();
duck.fly(); // Duck is flying!
duck.swim(); // Duck is swimming!
}
믹스인에 제약을 걸 수 있습니다.
mixin Logger on Animal {
void log(String msg) => print('[$name] $msg');
}
// Animal 또는 Animal 하위 클래스에만 적용 가능
class VerboseDog extends Animal with Logger {
VerboseDog(super.name);
void bark() {
log('Woof!');
}
}
열거형 (Enum)
// 기본 열거형
enum Direction { north, south, east, west }
// 고급 열거형 (Dart 2.17+)
enum Planet {
mercury(3.7),
venus(8.87),
earth(9.81);
final double gravity;
const Planet(this.gravity);
String get description => '${name}: ${gravity}m/s²';
}
void main() {
final d = Direction.north;
print(d.name); // north
print(d.index); // 0
// switch와 함께 (exhaustive 체크)
switch (d) {
case Direction.north:
print('Going north');
case Direction.south:
print('Going south');
case Direction.east || Direction.west:
print('Going east or west');
}
print(Planet.earth.description); // earth: 9.81m/s²
}
확장 메서드 (Extension)
기존 클래스에 메서드를 추가합니다. 클래스 수정 없이 기능을 확장합니다.
extension StringUtils on String {
bool get isEmail => contains('@') && contains('.');
String truncate(int maxLength) {
if (length <= maxLength) return this;
return '${substring(0, maxLength)}...';
}
String get capitalize =>
isEmpty ? this : '${this[0].toUpperCase()}${substring(1)}';
}
extension ListUtils<T> on List<T> {
T? get secondOrNull => length >= 2 ? this[1] : null;
List<List<T>> chunked(int size) {
final result = <List<T>>[];
for (var i = 0; i < length; i += size) {
result.add(sublist(i, (i + size).clamp(0, length)));
}
return result;
}
}
void main() {
print('[email protected]'.isEmail); // true
print('Hello World'.truncate(5)); // Hello...
print([1, 2, 3, 4, 5].chunked(2)); // [[1,2],[3,4],[5]]
}
정리
핵심 요점만 정리합니다.
factory생성자는 캐싱, JSON 파싱, 서브타입 반환에 유용합니다.abstract class는 공통 인터페이스와 부분 구현을,implements는 순수 인터페이스 계약을 표현합니다.mixin은 다중 상속 없이 여러 기능을 조합할 때 사용합니다.- 고급
enum은 값과 메서드를 함께 가질 수 있어 상태 표현에 강력합니다. extension으로 기존 클래스를 수정 없이 확장합니다.