일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- C언어 포인터
- Data Structure
- 플러터
- github
- jupyter lab
- C# delegate
- vim
- Algorithm
- c#
- Python
- gitlab
- c# 추상 클래스
- git
- 도커
- C++
- 다트 언어
- docker
- Houdini
- c# 윈폼
- 구조체
- dart 언어
- jupyter
- 깃
- c언어
- Flutter
- HTML
- c# winform
- Unity
- 유니티
- 포인터
- Today
- Total
nomad-programmer
[Programming/Dart] 다양한 Contructor (생성자) 본문
이름 있는 생성자 (Named Constructor)
이름 있는 생성자는 말 그대로 생성자에 이름을 부여한 것이다. 한 클래스 내에 많은 생성자를 생성하거나 생성자를 명확히 하기 위해서 사용할 수 있다.
class 클래스명 {
클래스명.생성자명() {
}
}
class Person {
Person.init() {
}
}
또한 이름 있는 생성자는 여러 생성자를 만들거나 생성자 내에서 값 체크 및 파싱 등 각종 작업을 할 때 유용하게 쓰인다. 다음의 예제를 살펴보자.
class Point {
double x, y;
// 일반적인 생성자
Point(this.x, this.y);
// 이름있는 생성자
Point.origin()
: x = 0,
y = 0;
// 이름있는 생성자
Point.fromJson(Map<String, double> json)
: x = json['x'],
y = json['y'] {
print('Point.fromJson: ($x, $y)');
}
}
void main() {
Point point1 = new Point(5, 8);
print('point1 -> (${point1.x}, ${point1.y})');
print('');
Point point2 = new Point.origin();
print('point2 -> (${point2.x}, ${point2.y})');
print('');
Map<String, double> json = <String, double>{};
json['x'] = 5.5;
json['y'] = 15.2;
Point point3 = new Point.fromJson(json);
print('point3 -> (${point3.x}, ${point3.y})');
}
/* 결과
point1 -> (5.0, 8.0)
point2 -> (0.0, 0.0)
Point.fromJson: (5.5, 15.2)
point3 -> (5.5, 15.2)
*/
이름 없는 생성자는 단 하나만 가질 수 있다. 또한 이름 있는 생성자를 선언하면 기본 생성자는 생략할 수 없다.
Point.origin() 은 이름 있는 생성자로서 x, y 변수를 0으로 초기화하는 역할을 수행한다. 그리고 Point.fromJson() 도 마찬가지로 이름 있는 생성자이며, 이 생성자는 json 형태의 Map 자료구조를 매개변수로 받아 변수 x, y를 초기화하는 생성자이다.
이처럼 이름 있는 생성자는 유용하게 사용된다. 또한 이름이 존재하여 생성자 오버로딩보다 코드의 가독성이 좋아진다.
참고로 ':' 키워드는 생성과 동시에 멤버 변수를 초기화하는데 쓰이는 키워드이다. 다음의 예제를 보자.
생성자 : 초기화 리스트 {
}
Person() : name = 'john', age = 18 {
}
대리 생성자 (Delegate Constructor)
생성자 호출 시 대리로 매개변수를 받아 다른 생성자를 호출한다. 쉽게 생각할 수 있는 것이이게 짧게 설명을 한다.
class Robot{
final double height;
Robot(this.height);
Robot.fromPlanet(String planet) : height = (planet == 'geometry') ? 2 : 7;
// 이 생성자가 호출되면 위의 Robot(this.height) 생성자가 호출된다. 즉, 이 생성자는
// 대리 생성자이다.
Robot.copy(Robot other) : this(other.height);
}
void main(){
print(new Robot.copy(Robot(5)).height);
print(new Robot.fromPlanet('geometry').height);
print(new Robot.fromPlanet('primitive').height);
}
/* 결과
5.0
2.0
7.0
*/
상수 생성자 (Const Constructor)
상수 생성자는 말 그대로 생성자를 상수처럼 만들어 준다. 이 말은 해당 클래스가 상수처럼 변하지 않는 객체를 생성한다는 것이다. 상수 생성자를 만들기 위해서는 인스턴스 변수가 모두 final로 선언되어야 한다. 또한 생성자는 const 키워드가 붙어야 한다. 다음의 예제를 보자.
class Person {
final String name;
final int age;
// const Person(this.name, this.age); 아래와 명령과 똑같은 의미다.
const Person(String name, int age)
: this.name = name,
this.age = age;
}
void main() {
Person person1 = const Person('john', 24);
Person person2 = const Person('john', 24);
Person person3 = new Person('john', 24);
Person person4 = new Person('john', 24);
print(identical(person1, person2));
print(identical(person2, person3));
print(identical(person3, person4));
}
/* 결과
true
false
flase
*/
identical() 메소드는 매개변수로 들어온 객체가 같은 인스턴스인지 비교해주는 메소드다. person1과 person2는 상수 생성자를 참조하고 있다. 따라서 동일한 인스턴스를 참조하고 있기 때문에 true가 된다. 그래서 Flutter 프레임워크를 사용하다보면 "const EdgeInset.all(5.0)" 이러한 코드를 볼 수 있다. 이것이 바로 상수 생성자이다. 메모리의 효율을 높여준다.
person3과 person4는 각각 새로운 인스턴스를 생성했기 때문에 동일한 인스턴스를 가지지 않는다. 어떠한 방식으로 인스턴스를 참조하고 있는지 아래의 그림을 보면 알 수 있다.
팩토리 생성자 (Factory Constructor)
팩토리 생성자는 팩토리 패턴을 쉽게 쓰기 위해 만들어졌다. 팩토리 패턴을 사용하면 해당 클래스의 인스턴스를 매번 생성하지 않아도 된다. 보통 자식 클래스의 인스턴스를 반환 받는다.
enum BookType { Fiction, Essay }
abstract class Book {
String getType() {
return 'Book';
}
String getTitle();
int getPage();
// 팩토리 생성자
factory Book(BookType type) {
switch (type) {
case BookType.Fiction:
return new FictionBook();
case BookType.Essay:
return new EssayBook();
default:
return null;
}
}
}
class FictionBook implements Book {
@override
int getPage() {
return 355;
}
@override
String getTitle() {
return 'About Time';
}
@override
String getType() {
return 'Fiction';
}
}
class EssayBook implements Book {
@override
int getPage() {
return 180;
}
@override
String getTitle() {
return 'World Coder';
}
@override
String getType() {
return 'Essay';
}
}
void main() {
Book fictionBook = new Book(BookType.Fiction);
Book essayBook = new Book(BookType.Essay);
print('제목: ${fictionBook.getTitle()}, '
'페이지: ${fictionBook.getPage()}, '
'장르: ${fictionBook.getType()}');
print('제목: ${essayBook.getTitle()}, '
'페이지: ${essayBook.getPage()}, '
'장르: ${essayBook.getType()}');
}
/* 결과
제목: About Time, 페이지: 355, 장르: Fiction
제목: World Coder, 페이지: 180, 장르: Essay
*/
factory 키워드를 쓰면 Singleton 패턴이나 Factory 패턴으로 객체를 작성할 때 유용하다. 다음은 Factory 패턴의 또 다른 예제 코드이다.
class PositivePoint extends Point {
double x, y;
PositivePoint(this.x, this.y) : super.init();
@override
void printPoints() {
print('x: $x, y: $y');
}
}
class NegativePoint extends Point {
double x, y;
NegativePoint(this.x, this.y) : super.init();
@override
void printPoints() {
print('x: $x, y: $y');
}
}
abstract class Point {
Point.init();
void printPoints();
factory Point(double x, double y) {
if ((x < 0) || (y < 0)) {
return NegativePoint(x, y);
}
return PositivePoint(x, y);
}
}
void main() {
Point p1 = Point(3, 5); // PositivePoint instance
Point p2 = Point(-1, 2); // NegativePoint instance
p1.printPoints();
p2.printPoints();
print('p1 -> $p1, p2 -> $p2');
}
/* 결과
x: 3.0, y: 5.0
x: -1.0, y: 2.0
p1 -> Instance of 'PositivePoint', p2 -> Instance of 'NegativePoint'
*/
'Programming > Dart' 카테고리의 다른 글
[Programming/Dart] 스트림 (Stream) (4) | 2020.10.16 |
---|---|
[Programming/Dart] 언어로 구현하는 싱글턴 패턴 (Singleton Pattern) (0) | 2020.10.13 |
[Programming/Dart] Stream : async*, yield (0) | 2020.10.10 |
[Programming/Dart] 비동기 프로그래밍 : futures, async, await (2) | 2020.10.10 |
[Programming/Dart] 유용한 기법 (계단식 표기법, 컬렉션 if, 컬렉션 for, null) (0) | 2020.10.06 |