Dart(1)에 이어서 객체지향 부분과 Generic 을 정리해보자.
Classes
기본적인 사항들
- 기본적으로 C++이나 Java의 상식을 크게 벗어나지 않는다.
- 클래스는 기본적으로 C++이나 Java랑 유사하게 생겼다.
- private 멤버는
_
를 앞에 붙인다.1
2
3class Test { int _private = 5; }
- 멤버에 접근할때는
.
과?.
을 쓸 수 있다.
Constructors
- 기본 생성자는 인자를 받지 않고, 부모의 생성자만 콜해준다.
- C++과 마찬가지로 생성자를 따로 만들면, 기본 생성자는 안생긴다.
- 생성자는 상속이 되지 않는다.
- 초기화용 생성자 문법이 있고, 매우 간단하다.
1
2
3
4class Point { num x, y; Point(this.x, this.y); }
- 함수 오버로딩도 안되는데, 당연히 생성자도 오버로딩이 안된다.
1
2
3
4
5
6
7
8class Point { num x, y; Point(this.x, this.y); Point(int x) { // error this.x = x; this.y = x; } }
- 대신에
Point.sym
처럼 이름을 덧붙여서 생성자를 여러개 생성할 수 있다.1
2
3
4
5
6
7
8class Point { num x, y; Point(this.x, this.y); Point.sym(int x) { this.x = x; this.y = x; } }
- C++의 Initializer List 같은 유사한 문법이 지원된다. Initializer List로 쓰려면
좌변(멤버변수) = 우변(리턴 값이 있는 식)
형태여야 한다.1
2
3
4
5
6class Point { num x, y; Point(this.x, this.y); Point.sym(int x) x = x, y = x; } }
- 몇가지 Initializer List와 같이 쓸 수 있는 예외가 있다.
assert
가 그중 하나.1
Point.sym(int x) x = x, y = x, assert(x >= 0);
super
도 Initializer List와 같이 쓸 수 있다. 부모의 생성자가 여러개라면 필연 위와같이 지정을 해주어야 한다.1
Point.sym(int x) x = x, y = x, super.sym();
- Redirecting constructors를 사용하면 다른 Constructor를 재사용 할 수 있다. 다만 Initializer List 및 함께 들어있는 assert와는 혼용 불가능하다. 에러난다.
1
2
3
4
5
6
7class Point { num x, y; Point(this.x, this.y); Point.sym1(int x): this(x,x); Point.sym2() : x=5, this(x,x); // error Point.sym3(int x): this(x,x), assert(x >= 0); //error }
factory
키워드를 쓰면 다른 인스턴스를 리턴해 줄 수 있다. Singleton이나 Factory Pattern으로 객체를 작성할 때 유용하다. 여기서 퍼왔음.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22class Point implements PointFactory { num x, y; Point(int x, int y): x=x,y=y; } class PointIn3rd implements PointFactory { num x, y; PointIn3rd(int x, int y): x=x,y=y; } abstract class PointFactory { factory PointFactory(int x, int y) { if (x < 0 && y < 0) return PointIn3rd(x,y); return Point(x,y); } } void main() { print(PointFactory(1,1)); //Instance of 'Point' print(PointFactory(-1,-1)); //Instance of 'PointIn3rd' }
Getter와 Setter
- getter와 setter를 get, set 키워드로 정해줄 수 있다. 이 함수들은 마치 변수처럼 사용할 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13class Point { int x, y; Point(this.x, this.y); int get dist => x*x + y*y; set both(int x) => this.x = this.y = x; } void main() { Point p = Point(1,2); print(p.dist); // 5 p.both = 3; print(p.dist); // 18 }
상속과 다형성
- 상속과 다형성은 거의 Java와 비슷하다.
- 상속은
extends
키워드를 통해서 한다. 다중상속 안됨. - 인터페이스를 강제할 때는
implements
키워드를 통해서 한다.- dart는 따로 interface 키워드가 없다. 때문에 class를 인터페이스로 전달한다.
implements
로 지정된 subclass는 전달된 class의 모든 함수와 변수를 재정의해야한다. 단 생성자는 제외이다.
abstract
를 활용해서 추상 클래스를 만든다.@override
annotation을 통해서 오버라이딩을 명시한다.- 원래 오버라이딩은 원본과 모든 인자의 타입이 같아야한다. 하지만 예외적으로
covariant
키워드를 통해서 타입을 더 좁힐(자녀 클래스) 수 있다.1
2
3
4
5
6
7
8
9class Animal { void chase(Animal x) { ... } } class Mouse extends Animal { ... } class Cat extends Animal { void chase(covariant Mouse x) { ... } }
mixin
을 활용하면 Feature를 추가할 수 있다. 다중으로 Feature를 사용할 수 있다.mixin
은class
와 거의 유사하게 사용하되, 생성자가 없다.class
선언 시with
키워드를 통해서 사용한다.1
2class Maestro extends Person with Musical, Aggressive, Demented {
Const, Static with class
const
로 생성한 경우, 상수 취급이 되고, 모든 멤버가const
이다.const
로 생성한 Instance의 모든 필드가 같을 경우, 같은 오브젝트 취급한다.1
2
3
4var a = const ImmutablePoint(1, 1); var b = const ImmutablePoint(1, 1); assert(identical(a, b)); // They are the same instance!
const
를 붙인 생성자는 아예const
Instance를 생성해버린다. 대신 모든 멤버는 final로 선언되어 있어야 한다.1
2
3
4class ImmutablePoint { final num x, y; const ImmutablePoint(this.x, this.y); }
static
으로 지정하면 정적 함수나 변수가 된다. Instance화 시키지 않고 사용할 수 있다. C++의 그것과 똑같다.
Generics
- Java의 Generic과 거의 같다.
- Java에서 처럼 타입 안정성, 코드 중복 제거를 위한 목적으로 쓴다.
1
2
3var names = <String>['Seth', 'Kathy', 'Lars']; names.add("123"); names.add(123); // error
- Java와 달리 모든 타입이 Object이기 때문에 굳이 Wrapper들을 안써도 된다.
- 코드 중복 제거의 예시는 아래와 같다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14class Vector<T extends num> { T x, y; Vector(this.x, this.y); T get w => x*x + y*y; } void main() { var intVector = Vector(1,2); // 다만 아래와 같이 쓰는게 권장된다. // Vector<int> intVector = Vector<int>(1,2); var floatVector = Vector(2.5, 1.5); print(intVector.w); print(floatVector.w); }
Asynchrony support
- Flutter와 연관이 깊어지는 비동기 부분이다.
Future
- 비동기 값을 저장할 때 쓴다.
- JavaScript에서 쓰던 것 처럼,
then
과catchError
로 콜백을 넘기면 된다.1
2
3Future<int> future = getFuture(); future.then((value) => handleValue(value)) .catchError((error) => handleError(error));