이번 장은 다트 언어로 객체지향 프로그래밍에 대해 소개한다.
class Idol {
String name = '블랙핑크';
void sayName() {
print('저는 ${this.name}입니다.');
print('저는 $name입니다.'); // 스코프안에 name이 하나만 있다면 this 생략 가능
}
}
void main() {
Idol blackPink = Idol();
blackPink.sayName();
}
생성자에서 입력받을 변수를 일반적으로 final로 선언합니다.
인스턴스화한 다음에 혹시라도 변수의 값을 변경하는 실수를 막기 위함입니다.
생성자는 클래스와 같은 이름으로 선언합니다.
class Idol {
final String name;
Idol(String name) : this.name = name;
// Idol(this.name); this를 사용할 경우 해당되는 변수에 자동으로 저장됩니다.
void sayName() {
print('저는 ${this.name}입니다.');
}
}
void main() {
Idol blackPick = Idol('블랙핑크');
blackPink.sayName();
}
네임드 생정자는 네임드 파라미터와 비슷한 개념입니다.
일반적으로 클래스를 생성하는 여러 방법을 명시하고 싶을 때 사용합니다.
아래 예시는 일반적인 생성자와 Map을 파라미터로 받는 생성자를 보여줍니다.
class Idol {
final String name;
final int memberCount;
Idol(String name, int memberCount)
: this.name = name, // , 기호로 여러 변수를 저장할 수 있습니다.
this.memberCount = memberCount;
// Idol (this.name, this.memberCount);
Idol.fromMap(Map<String, dynamic> map)
: this.name = map['name'],
this.memberCount = map['memberCount'];
void sayName() {
print('이름은 $name이고 $memberCount명입니다.');
}
}
void main() {
Idol blackPink = Idol('블랙핑크', 4);
blackPink.sayName();
Idol bts = Idol.fromMap({
'name': 'BTS',
'memberCount': 7,
});
bts.sayName(); // 이름은 BTS이고 7명입니다.
}
다트에서 프라이빗 변수는 클래스 내부에서만 사용하는 변수가 아닌, 같은 파일에서만 접근 가능한 변수입니다.
class Idol {
String _name;
Idol(this._name);
}
void main() {
Idol blackPink = Idol('블랙핑크');
print(blackPink._name); // 같은 파일에서는 _name에 접근 가능하지만, 다른 파일에선 불가능 합니다.
}
class Idol {
String _name;
Idol(this._name);
String get name {
return this._name;
}
set name(String name) {
this._name = name;
}
}
void main() {
Idol blackPink = Idol('블랙핑크');
blackPink.name = '에이핑크';
print(blackPick.name); // 에이핑크
}
class Idol {
final String name;
Idol(this.name);
void sayName() {
print('저는 $name입니다.');
}
}
class BoyGroup extends Idol {
BoyGroup(String name) : super(name);
// BoyGroup(super.name);
void sayMale() {
print('저는 남자 아이돌입니다.');
}
}
void main() {
BoyGroup bts = BoyGroup('BTS');
bts.sayName();
bts.sayMale();
}
class GirlGroup extends Idol {
GirlGroup(super.name);
void sayName() {
print('저는 여자 아이돌 $name입니다.');
}
}
void main() {
GirlGroup blackPink = GirlGroup('블랙핑크');
blackPink.sayName(); // 저는 여자 아이돌 블랙핑크입니다.
}
인터페이스는 변수, 메서드의 이름만 같고 모든 기능은 새로 다시 정의해주어야 합니다.
인터페이스는 특정 클래스가 반드시 같은 이름을 같는 변수와 메서드를 사용해야할 때 유용합니다.
class Idol {
final String name;
void sayName() {}
}
class GirlGroup implements Idol {
final String name;
GirlGroup (this.name);
void sayName() {
print('저는 여자 아이돌 $name입니다.');
}
}
void main() {
GirlGroup blackPink = GirlGroup('블랙핑크');
blackPink.sayName();
}
믹스인은 특정 클래스에 원하는 기능들만 골라넣을 수 있는 기능입니다.
mixin IdolSingMixin on Idol {
void sing() {
print('$name이 노래를 부릅니다.');
}
}
class BoyGroup extends Idol with IdolSingMixin {
BoyGroup(super.name);
void sayMale() {
print('저는 남자 아이돌입니다.');
}
}
void main() {
BoyGroup bts = BoyGroup('BTS');
bts.sing();
}
추상 클래스는 변수, 메서드 이름만 정의되어 있고, implements나 extends를 통해 기능을 정의하거나 추가합니다.
abstract class Idol {
final String name;
Idol(this.name);
void sayName();
}
class GirlGroup implements Idol {
final String name;
GirlGroup(this.name);
void sayName() {
print('$name입니다.');
}
}
void main() {
GirlGroup blackPink = GirlGroup('블랙핑크');
blackPink.sayName();
}
제네릭은 클래스나 함수의 정의를 선언할 때가 아니라 인스턴스화 하거나 실행할 때로 미룹니다.
특정 변수의 타입을 하나의 타입으로 제한하고 싶지 않을 때 자주 사용합니다.
class Cache<T> {
final T data;
Cache({
required this.data,
});
}
void main() {
final cache = Cache<List<int>>(
data: [1, 2, 3],
);
print(cache.data.reduce((v, e) => v + e)); // 6
}
static은 인스턴스끼리 공유해야하는 정보를 위해 사용합니다.
class Counter {
static int i = 0;
Counter() {
print(i++);
}
}
void main() {
Counter count1 = Counter(); // 1
Counter count2 = Counter(); // 2
}
캐스케이드 연산자는 인스턴스에서 해당 인스턴스의 속성이나 멤버 함수를 연속해서 사용하는 기능입니다.
... 기호를 사용합니다.
void main() {
Idol blackPink = Idol('블랙핑크')
...sayName(); // 저는 블랙핑크입니다.
blackPick...sayName()...sayMemeberCount();
}
《Must Have 코드팩토리의 플러터 프로그래밍 2판》의 스터디 내용 입니다.