Casacade Notation은 Dart에서 객체를 연속적으로 수정하거나 메소드를 호출하는 편리한 방법을 제공하는 기능이다.
..
연산자를 사용하여 동일한 객체에 대해 여러 동작을 수행할 수 있다.
class Player {
String name;
int age;
String team;
void sayHello() {
print('Hi, my name is $name. I am team $team, and I`m $age.');
}
Player({
required this.name,
required this.age,
required this.team
});
}
void main() {
var player1 = Player(
name: '지은',
age: 27,
team: 'blue'
) // 세미콜론 삭제
..sayHello() // Hi, my name is 지은. I am team blue, and I`m 27.
..name = '지지'
..age = 13
..team = 'red'
..sayHello(); // Hi, my name is 지지 from team red, and I`m 13.
}
위의 코드에서 player1
객체를 생성하고, Casacade Notation을 사용하여 해당 객체의 name
, age
, team
속성을 수정하고 sayHello
메소드를 호출했다.
Dart에서 enum을 선언하는 법은 다음과 같다.
enum을 선언할 때에는 각 상수의 타입을 따로 지정할 필요는 없다. Dart가 각 상수에 대한 타입을 자동으로 부여한다.
enum Team { red, blue }
enum XP { beginner, medium, pro }
이렇게 선언한 enum을 클래스를 선언할 때도 사용할 수 있다.
class Player {
String name;
XP xp;
Team team;
Player({
required this.name,
required this.xp,
required this.team,
});
}
void main() {
var jieun = Player(name: 'Jieun', xp: XP.biginner, team: Team.red);
}
Abstract Class는 일부 메소드의 선언을 포함하고 있지만 그 구현은 직접 제공하지 않는 클래스로, 다른 클래스들이 이 abstract class를 상속하여 해당 메소드를 구현할 수 있다.
// 추상화 클래스는 다른 클래스들의 청사진으로 사용된다.
// 메소드 선언과 리턴 타입만 작성한다.
abstract class Human {
void walk();
}
class Player extends Human {
String name;
Player({
required this.name
});
void walk() {
print('player is walking');
}
}
class Coach extends Human {
String name;
Coach({
required this.name
});
void walk() {
print('coach is walking');
}
}
void main() {
var jieun = Player(name: 'Jieun');
var woo = Coach(name: 'woo');
jieun.walk(); //player is walking
woo.walk(); // coach is walking
}
상속을 사용하면 하위 클래스에서 상위 클래스의 필드와 메소드를 상속받아 사용할 수 있다.
하위 클래스(Player
)의 생성자에서 super
키워드를 사용해 상위 클래스인 Human
의 생성자를 호출할 수 있다. 이를 통해 상위 클래스(Human
)의 필드인 name
에 값을 전달한다.
class Human {
final String name;
Human({
required this.name
});
void sayHello() {
print('Hello, my name is $name'.);
}
}
enum Team {red, blue}
class Player extends Human {
final Team team;
Player({
required this.team,
required String name
}) : super(name: name); // super 생성자를 호출하여 부모 클래스에 name 변수를 전달
}
void main() {
var jieun = Player(
team: Team.red,
name: 'Jieun'
);
jieun.sayHello(); // sayHello를 상속받아 사용할 수 있다.
}
상속에서 override
키워드를 사용해 하위 클래스에서 상위 클래스의 메소드나 속성을 덮어쓸 수 있다.
class Player extends Human {
final Team team;
Player({
required this.team,
required String name
}) : super(name: name);
void sayHello() {
super.sayHello();
print('and I play for ${team}'); // override
}
}
void main() {
var jieun = Player(
team: Team.red,
name: 'Jieun'
);
jieun.sayHello(); // Hello, my name is Jieun.
// and I play for Team.red
}
위의 코드는 Player
클래스에서 sayHello
메소드를 override하여, 메소드 내에서 super.sayHello();
를 통해 상위 클래스인 Human
클래스의 sayHello 메소드를 호출하고, 그 뒤에 "and I play for Team.red"를 출력한다.
따라서 sayHello
메소드 호출 시 두 개의 문장이 출력된다.
만약 sayHello
메소드를 완전히 덮어쓰고 싶다면 아래처럼 작성하면 된다.
void sayHello() {
print('and I play for ${team}'); // and I play for Team.red
}
Mixin은 생성자가 없는 클래스로, 여러 클래스에 프로퍼티나 메소드를 추가할 때 유용하다.
// Mixin은 여러 클래스에 재사용이 가능하다
mixin Strong {
final double strengthLevel = 1500.99;
}
mixin QuickRunner {
void runQuick() {
print('runnnnnnnnnnnn!');
}
}
mixin Tall {
final double height = 1.99;
}
enum Team {red, blue}
class Player with Strong, QuickRunner, Tall {
final Team team;
Player({
required this.team
});
}
class Horse with Strong, QuickRunner {}
class Kid with QuickRunner {}
void main() {
var player = Player(
team: Team.red,
);
player.runQuick(); // runnnnnnnnnnnn!
var horse = Horse();
print(horse.strengthLevel); // 1500.99
}
상속과 mixin의 차이점
둘 다 코드를 재사용하고 모듈화하는 데 사용된다는 점은 같지만,
- 상속은
extends
키워드를 사용하여 부모 클래스의 특성을 하위 클래스에 확장하고, 하위 클래스의 인스턴스는 동시에 상위 클래스의 인스턴스가 된다.- Mixin은
with
키워드를 사용해 단순히 Mixin의 프로퍼티와 메소드를 가져오는 것이다.