Mixin이란 무엇인가
Mixin은 코드 재사용 기법으로, 서로 상속 관계 없는 클래스 계열에서 코드를 공유할 수 있게 해줍니다. 여러 클래스에 일괄적으로 멤버 구현을 제공하는 것이 목표입니다. 다중 상속과 비슷해 보이지만, 본래 목적은 클래스에 독립적인 모듈 기능들을 추가하는 것입니다.
Mixin 사용하기
키워드 with 뒤에 하나 이상의 Mixin 이름을 적어줍니다.
class Musician extends Performer with Musical {
// 코드
}
class Maestro extends Person with Musical, Aggressive, Demented {
Maestro(String maestroName) {
name = maestroName;
canConduct = true;
}
}
Code language: Dart (dart)
Mixin 정의하기
mixin 키워드로 선언합니다.
참고:
mixin class(Dart 3.0 이상) 일반 클래스이자 Mixin으로 함께 활용 가능합니다.
강제 규칙
mixin/mixin class안에extends를 쓸 수 없음- 생성자(generative constructor)를 선언할 수 없음
mixin Musical {
bool canPlayPiano = false;
bool canCompose = false;
bool canConduct = false;
void entertainMe() {
if (canPlayPiano) {
print('Playing piano');
} else if (canConduct) {
print('Waving hands');
} else {
print('Humming to self');
}
}
}
class Musician with Musical {}
void main() {
var m = Musician();
m.canConduct = true;
m.entertainMe(); // Waving hands
}
Code language: Dart (dart)
실행 결과
D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
Musician is playing
Musician is playingCode language: CSS (css)
Mixin이 외부 멤버를 호출해야 하는 경우
Mixin 자체에 구현되지 않은 메서드 / 속성
Mixin은 자체 구현이 없는 멤버를 호출해야 하는 상황이 자주 발생하며, 여기 표준 해결 방안 4가지를 소개합니다.
Mixin 내부에 추상 멤버 정의
Mixin에 추상 메서드를 선언하면, 이 Mixin을 사용하는 모든 클래스는 해당 추상 메서드를 구현해야 합니다.
mixin Musician {
// 추상 메서드, 사용 측에서 구현 필수
void playInstrument(String instrumentName);
void playPiano() {
playInstrument('Piano');
}
void playFlute() {
playInstrument('Flute');
}
}
// 사용 클래스는 반드시 재정의하여 구현
class Virtuoso with Musician {
@override
void playInstrument(String instrumentName) {
print('Plays the $instrumentName beautifully');
}
}
void main() {
var artist = Virtuoso();
artist.playPiano();
artist.playFlute();
}
Code language: Dart (dart)
Plays the Piano beautifully
Plays the Flute beautifully
추상 Getter로 호스트 클래스 상태 접근
Mixin에 추상 getter를 정의해 호스트 클래스의 필드를 읽어 다른 클래스의 상태에 접근할 수 있습니다.
/// name 속성을 가진 모든 클래스에 믹스인 가능, name 기반 == 연산자와 hashCode 자동 제공
mixin NameIdentity {
String get name;
@override
int get hashCode => name.hashCode;
@override
bool operator ==(Object other) =>
other is NameIdentity && name == other.name;
}
class Person with NameIdentity {
final String name;
Person(this.name);
}
void main() {
var p1 = Person("Alice");
var p2 = Person("Alice");
var p3 = Person("Bob");
print(p1 == p2); // true
print(p1 == p3); // false
}
Code language: JavaScript (javascript)
Mixin에서 인터페이스 implements 구현
Mixin에 implements로 인터페이스를 제약하면, 믹스인하는 클래스는 인터페이스의 모든 메서드를 구현해야 합니다.
abstract interface class Tuner {
void tuneInstrument();
}
mixin Guitarist implements Tuner {
void playSong() {
tuneInstrument();
print('Strums guitar majestically.');
}
}
class PunkRocker with Guitarist {
@override
void tuneInstrument() {
print("Don't bother, being out of tune is punk rock.");
}
}
void main() {
PunkRocker().playSong();
}
Code language: JavaScript (javascript)
Don't bother, being out of tune is punk rock.
Strums guitar majestically.
on 절: 특정 부모 클래스의 자식에서만 Mixin 사용 제한
on의 역할: 지정한 타입을 상속받은 클래스만 이 Mixin을 사용할 수 있도록 제한.
또한 Mixin 안에서 부모 클래스의 멤버 호출, super.xxx() 호출도 가능해집니다.
Mixin 내부에서
super로 부모 메서드를 호출해야 할 때만on을 사용하세요!
class Musician {
void musicianMethod() {
print('Playing music!');
}
}
// Musician의 자식 클래스에만 믹스인 가능
mixin MusicalPerformer on Musician {
void performerMethod() {
print('Performing music!');
super.musicianMethod(); // on으로 제약된 부모 메서드 호출 가능
}
}
// SingerDancer는 Musician을 상속하므로 MusicalPerformer 믹스인 가능
class SingerDancer extends Musician with MusicalPerformer {}
void main() {
SingerDancer().performerMethod();
}
Code language: Dart (dart)
Performing music!
Playing music!
SingerDancer에 MusicalPerformer를 믹스인했으므로 내부의 performerMethod 메서드를 사용할 수 있습니다.
믹스인은 간단히 말해 한 클래스가 다른 Mixin의 메서드를 가져와 자기 것처럼 쓸 수 있는 기능입니다.
⚠️ 잘못된 예시:
클래스가
Musician을 상속하지 않은 상태에서 직접with MusicalPerformer를 사용하면 컴파일 오류가 발생합니다.
class /mixin/mixin class 차이점
mixin: 오직with로 사용 가능,extends로 상속할 수 없음class:extends상속 가능, 직접 mixin으로 쓸 수 없음mixin class:with을 써서 Mixin으로 활용 가능extends로 일반 부모 클래스로도 활용 가능
적용되는 제약 사항:
- mixin / mixin class 내부에 extends, with 선언 불가
- class / mixin class 내부에 on 선언 불가
mixin class Musician { void play() { print("Musician is playing"); } } // Mixin으로 사용 class Novice1 with Musician {} // 일반 부모 클래스로 상속 class Novice2 extends Musician {} void main() { Novice1().play(); Novice2().play(); }Code language: Dart (dart)실행 결과
D:\dartdemo\firstdart>dart run Building package executable... Built firstdart:firstdart. Musician is playing Musician is playingCode language: CSS (css)Mixins
Previous: 클래스 상속과 멤버 재정의Next: 열거형