Dart에서 가장 중요!
function내에서 variable을 사용할 때는 데이터 타입을 꼭 명시해줄 필요 없었음 (var)
class 선언할 때는 타입 꼭 명시해줘야 함!
class Player {
String name = 'atlns';
int xp = 1500;
}
void main() {
var player = Player();
print(player.name);
player.name = 'snlta';
print(player.name); // Player의 이름이 변경됨
}
위의 예시에서는 Player의 이름을 바꿀 수 있었지만, 바꾸지 못하게 하려면 final
키워드 이용하면 됨
다른 언어처럼 this를 사용해도 동작하지만 Dart에서는 Class method 내에서의 this는 권장하지X
class Player {
final String name = 'atlns';
int xp = 1500;
void sayHello(){
// print("Hi my name is ${this.name}");
// 다른 언어처럼 this를 사용해도 동작하지만
// Dart에서는 Class method 내에서의 this는 권장하지X
print("Hi, my name is $name");
}
}
void main() {
var player = Player();
player.sayHello();
}
예외) method 내에 같은 이름의 variable이 있는 경우(variable과 class property의 이름이 겹치는 경우) this 사용
class Player {
final String name = 'atlns';
int xp = 1500;
void sayHello(){
var name = 'ana';
print("name: $name"); // ana
print("Hi, my name is ${this.name}"); // atlns
}
}
void main() {
var player = Player();
player.sayHello();
}
위의 예제를 변경해 argument로 player의 이름과 xp를 전달해서 새로운 Player를 생성해보자
// [효율적이지 않은 코드]
class Player {
// late 없으면 Error
// non-nullable instance field 'name', 'xp' must be initialized
late final String name;
late int xp;
Player(String name, int xp){
this.name = name;
this.xp = xp;
}
void sayHello(){
print("Hi, my name is $name");
}
}
void main() {
var player = Player('atlns', 1500);
player.sayHello();
var player2 = Player('bada', 2400);
player2.sayHello();
}
하지만 너무 반복적인 작업
name이 String이고, xp가 int 타입이라고 이미 명시했기 때문에 late을 지우고 아래와 같이 작성해주는 게 더 효율적!
class Player {
final String name;
int xp;
Player(this.name, this.xp);
void sayHello(){
print("Hi, my name is $name");
}
}
void main() {
var player = Player('atlns', 1500);
player.sayHello();
var player2 = Player('bada', 2400);
player2.sayHello();
}
class가 클 때 위와 같은 positional parameter를 사용하면 컨트롤이 어려움 (순서를 지켜서 argument 넘겨줘야 되니까)
named parameter를 가진 constructor로 바꿔주자!
class Player {
final String name;
int xp;
String team;
int age;
Player({ // 중괄호 추가
required this.name,
required this.xp,
required this.team,
required this.age,
});
// required 키워드 없으면 Error (다른 해결 방법은 초기값 대입이지만 여기선 좋지 않은 해결방법)
// The parameter '' can't have a value of 'null' because of its type, but the implicit value is 'null'.
void sayHello() {
print("Hi, my name is $name");
}
}
void main() {
var player = Player(
name: 'atlns',
xp: 1500,
team: 'red',
age: 23,
);
player.sayHello();
var player2 = Player(
name: 'bada',
age: 28,
team: 'blue',
xp: 2400,
);
player2.sayHello();
}
Positional parameter는 required가 default이기 때문에 필요X
Flutter에서 정말 많이 사용됨!
Player.createBluePlayer({
// 콜론(:)을 사용해서 Player 클래스 초기화
required String name,
required int age,
}) : this.age = age,
this.name = name,
this.team = 'blue',
this.xp = 0;
// positional parameter는 required가 default
Player.createRedPlayer(String name, int age)
: this.age = age,
this.name = name,
this.team = 'red',
this.xp = 0;
위와 같은 형태를 사용해서 named constructor 생성
class Player {
final String name;
int xp, age;
String team;
Player({
required this.name,
required this.xp,
required this.team,
required this.age,
});
Player.createBluePlayer({
// 콜론(:)을 사용해서 Player 클래스 초기화
required String name,
required int age,
}) : this.age = age,
this.name = name,
this.team = 'blue',
this.xp = 0;
// positional parameter는 required가 default
Player.createRedPlayer(String name, int age)
: this.age = age,
this.name = name,
this.team = 'red',
this.xp = 0;
void sayHello() {
print("Hi, my name is $name");
}
}
void main() {
var player = Player.createBluePlayer(
name: 'atlns',
age: 23,
);
player.sayHello();
var player2 = Player.createRedPlayer('bada', 28);
player2.sayHello();
}
API data를 사용할 경우 아래처럼 작성할 수 있음
class Player {
final String name;
int xp;
String team;
Player.fromJson(Map<String, dynamic> playerJson)
: name = playerJson['name'],
xp = playerJson['xp'],
team = playerJson['team'];
void sayHello() {
print("Hi, my name is $name");
}
}
void main() {
var apiData = [
{
"name": "atlns",
"team": "red",
"xp": 0,
},
{
"name": "bada",
"team": "red",
"xp": 0,
},
{
"name": "cloud",
"team": "red",
"xp": 0,
},
];
apiData.forEach((playerJson) {
var player = Player.fromJson(playerJson);
player.sayHello();
});
}
class Player {
String name, team;
int xp;
Player({
required this.name,
required this.xp,
required this.team,
});
void sayHello() {
print("Hi, my name is $name");
}
}
void main() {
var atlns = Player(name: 'atlns', xp: 1500, team: 'red');
atlns.name = 'bada';
atlns.xp = 250000;
atlns.team = 'blue';
}
위의 경우 main에서 반복되는 코드를 줄이기 위해 cascade notation을 쓸 수 있다.
var atlns = Player(name: 'atlns', xp: 1500, team: 'red')
..name = 'bada'
..xp = 250000
..team = 'blue'
..sayHello();
Player object를 생성한 뒤 세미콜론을 작성하지 않은 채로, ..
을 사용하면 이는 바로 앞의 class를 가리키게 된다.
만약 Player object를 생성한 후 cascade notation을 뒤에서 사용하고 싶다면 아래와 같이 쓸 수 있다.
var atlns = Player(name: 'atlns', xp: 1500, team: 'red');
var bada = atlns
..name = 'bada'
..xp = 250000
..team = 'blue'
..sayHello();
Flutter에서 많이 사용됨
데이터를 잘못 적는 실수를 방지해줌
enum Team { red, blue } // "" 안 써줘도 됨
enum XPLevel { beginner, medium, pro }
class Player {
String name;
XPLevel xp;
Team team; // 이제 String이 아닌 enum
Player({
required this.name,
required this.xp,
required this.team,
});
void sayHello() {
print("Hi, my name is $name");
}
}
void main() {
var atlns = Player(name: 'atlns', xp: XPLevel.beginner, team: Team.red);
var bada = atlns
..name = 'bada'
..xp = XPLevel.pro
..team = Team.blue
..sayHello();
}
Flutter에서 많이 쓰이지 않지만 유용
추상화 클래스는 다른 클래스들이 어떤 blueprint를 가지고 있어야 하는지 정의해주기 때문에 매우 유용
extends
)추상화 클래스는 이를 상속받는 모든 클래스가 가지고 있어야 하는 메소드를 정의/강제하기 때문에, 상속받는 클래스에서 해당 메소드를 구현하지 않으면 에러가 발생한다.
abstract class Human {
void walk();
}
...
class Player extends Human{
...
void walk(){
print("I'm walking");
}
...
}
class Coach extends Human{
void walk(){
print('The coach is walking');
}
}
Flutter에서 자주 쓰이진 않지만 꼭 알아둬야 하는 중요한 개념
부모클래스의 생성자 함수를 호출해야 한다.
자식클래스는 부모클래스의 instance가 되고, 부모클래스의 property와 메소드를 가져온다.
class Human {
final String name;
Human({required this.name});
void sayHello() {
print("Hi, my name is $name");
}
}
enum Team { red, blue }
class Player extends Human {
final Team team;
Player({
required this.team,
required String name,
// Player 생성자 함수에 있는 name을 부모클래스인 Human으로 전달
// super 키워드를 통해 확장한 부모 클래스와 상호작용 (부모 클래스의 프로퍼티에 접근하거나 메소드 호출 가능하게)
}) : super(name: name); // 객체지향프로그래밍(OOP) 개념
void sayHello() {
super.sayHello();
print("and I play for $team");
}
}
void main() {
var player = Player(team: Team.red, name:'atlns');
player.sayHello();
}
제일 중요한 점은, 확장한 부모 클래스가 생성자를 포함하고 있을 때, 그 클래스를 자식 클래스가 사용하려면 필요한 값을 전달해야 하고 부모 클래스의 생성자를 호출해줘야 함
super(name: name)
Flutter에서 자주 사용됨
Mixin
: 생성자가 없는 클래스 ⇒ super 필요X
with
키워드로 Mixin 클래스의 property와 method를 가져올 수 있음
클래스에 property 추가할 때 매우 유용
Mixin의 핵심은 여러 클래스에 재사용이 가능하다는 점
mixin Strong {
final double strengthLevel = 1234.56;
}
mixin QuickRunner {
void runQuick() {
print("runnnnn");
}
}
mixin Tall {
final double height = 176.4;
}
enum Team { red, blue }
class Horse with Strong, QuickRunner {}
class Kid with QuickRunner {}
class Player with Strong, QuickRunner, Tall {
final Team team;
Player({
required this.team,
required String name,
});
}
void main() {
var player = Player(
name: 'atlns',
team: Team.red,
);
player.runQuick();
}