class StudyMembers{
String study = 'Flutter & Dart';
String? name;
int? age;
String? location;
bool? prior;
}
void main(){
StudyMembers member1 = StudyMembers();
member1.name = '5yattree';
member1.age = 100;
member1.location = 'Seoul';
member1.prior = false;
print(member1.study);
print(member1.name);
}
위의 코드는 Flutter와 Dart를 함께 공부하는 스터디 멤버들의 속성을 정의하기 위해 작성한 Class(클래스)이며 또한 이렇게 작성한 Class(클래스)를 이용하여 Constructor(생성자)를 통해 새로운 Instance(인스턴스)를 생성한 것을 이해하기 위해서 작성한 코드이다.
class StudyMembers{
String study = 'Flutter & Dart';
String? name;
int? age;
String? location;
bool? prior;
// 이 클래스 내의 속성 즉, study, name, age, location, prior는 멤버 변수라고 한다.
}
Class(클래스)의 내부를 살펴보면 스티디 멤버들이 어떤 것을 공부하는지 또 스터디 멤버의 이름과 나이, 사는 지역과 이전의 프로그래밍 경험등을 속성(아규먼트,Argument)으로 가질 수 있도록 작성하였다. 이와 같은 속성들 즉, Class(클래스) 내부의 변수는 또 다른 말로 Member Variable(멤버 변수)라고도 한다.
*String?, int?, bool? 뒤의 물음표(?)를 넣어둔 건 Null Safety를 적용하기 위함으로 Nullable한 변수로써 지정하기 위함.
void main(){
StudyMembers member1 = StudyMembers();
member1.name = '5yattree';
member1.age = 100;
member1.location = 'Seoul';
member1.prior = false;
print(member1.study); // "Flutter & Dart"
print(member1.name); // "5yattree"
}
main() 함수 내부의 코드를 살펴보면
StudyMembers member1 = StudyMembers(); 구문에서 생성자를 통해 member1 이라는 인스턴스를 생성하고 각각 속성의 데이터를 정의하는 것을 확인할 수 있다. 예시에서는 스터디 멤버인 member1은 생성자를 통해 새롭게 생성된 인스턴스로 5yattree라는 이름과 100살의 나이, 또 서울에 거주하며 이전에 프로그래밍 경험이 없는 것으로 정의되어 각 변수에 값이 할당되었다.
class StudyMembers{
String study = 'Flutter & Dart';
String? name;
int? age;
String? location;
bool? prior;
}
사실 작성한 위의 Class(클래스) 코드에서는 멤버 변수외에 별도 따로 작성한 부분은 존재하지 않는다.
하지만 우리 눈에 보이지 않을 뿐 Dart 프로그래밍 언어가 알아서 Default Constructor(기본 생성자)라는 것을 만들어 둔다.
class StudyMembers{
String study = 'Flutter & Dart';
String? name;
int? age;
String? location;
bool? prior;
// 실제로 눈에 보이진 않지만 Default Constructor(기본 생성자)는 존재하며 있다.
// StudyMembers();
// StudyMembers(){}
}
void main(){
StudyMembers member1 = StudyMembers();
print(member1.study); // Flutter & Dart 출력
print(member1.name); // null 출력
print(member1.age); // null 출력
print(member1.location); // null 출력
print(member1.prior); // null 출력
member1.name = '5yattree';
member1.age = 100;
member1.location = 'Seoul';
member1.prior = false;
print(member1.study); // Flutter & Dart 출력
print(member1.name); // 5yattree 출력
print(member1.age); // 100 출력
print(member1.location); // Seoul 출력
print(member1.prior); // false 출력
}
따라서 위의 기본 생성자를 통해 만들어진 처음의 member1 인스턴스는 Class(클래스)에서 사전에 정의된 데이터를 토대로 생성되는 것으로 이해할 수 있고, 이렇게 생성된 인스턴스의 각 변수에는 다시 값을 할당하여 이용 수 있는 것으로 이해할 수 있다.
그러나 이렇게 매번 Class(클래스)와 Constructor(생성자)를 통해서 인스턴스를 생성할 때마다 각각의 변수를 일일히 할당하는 것은 어쩌면 비효율적이고 번거로운 일이 될 수 있다. 따라서 이런 경우 Class(클래스)내의 Constructor(생성자)를 직접 정의하여 새롭게 이용할 수 있다.
class StudyMembers{
String study = 'Flutter & Dart';
String? name;
int? age;
String? location;
bool? prior;
StudyMembers(String name, int age, String location, bool prior){
this.name = name;
this.age = age;
this.location = location;
this.prior = prior;
}
// StudyMembers(this.name, this.age, this.location, this.prior); 다른 표현. V
// StudyMembers(this.name, this.age, this.location, this.prior){} 다른 표현.
}
void main(){
StudyMembers member1 = StudyMembers('5yattree', 100, 'Seoul', false);
StudyMembers member2 = StudyMembers('Yesol', 100, 'Jeju', true);
print(member1.study); // Flutter & Dart 출력
print(member1.name); // 5yatree 출력
print(member1.age); // 100 출력
print(member1.location); // Seoul 출력
print(member1.prior); // false 출력
print(member2.study); // Flutter & Dart 출력
print(member2.name); // Yesol 출력
print(member2.age); // 100 출력
print(member2.location); // Jeju 출력
print(member2.prior); // true 출력
}
StudyMembers 클래스 내에 생성자를 직접 정의하였고 이렇게 새롭게 정의한 생성자를 통해서
호출된 생성자에게 각 아규먼트의 순서와 데이터 타입에 맞게 값을 할당하여 새로운 인스턴스를 생성할 수 있다.
만일 아규먼트의 순서와 데이터 타입이 일치하지 않는다면 오류가 발생하므로 주의
이처럼 생성자를 새롭게 정의하여 일일히 번거롭게 인스턴스를 생성하고 변수의 값을 할당하는 작업을 진행하지 않고 한번에 인스턴스를 생성할 수 있지만 만약 아규먼트의 갯수가 30개, 40개, 100개로 비교적 많다면?
또 새로운 인스턴스를 생성자를 통해 생성할 때 100개의 아규먼트 중 3,4개 정도만 입력받고 싶다면?
현재 생성자로는 아규먼트가 몇개 이건 반드시 순서를 지키며 모든 값을 입력 해야하는데...
이를 해결하기 위해서 만들어진 네임드 아규먼트 (Named Argument)
class StudyMembers{
String study = 'Flutter & Dart';
String? name;
int? age;
String? location;
bool? prior;
StudyMembers({String? name, int? age, String? location, bool? prior}){
this.name = name;
this.age = age;
this.location = location;
this.prior = prior;
}
// StudyMembers({String? name, int? age, String? location, bool? prior}); 다른 표현. V
// StudyMembers({String? name, int? age, String? location, bool? prior}){} 다른 표현.
// {} 생성자 내의 아규먼트들을 중괄호 Curly Brackets 로 감싸서 아규먼트들을 선택 사항으로 이용.
}
void main(){
StudyMembers member1 = StudyMembers(name: '5yattree');
StudyMembers member2 = StudyMembers(age: 100);
print(member1.name); // 5yatree 출력
print(member2.age); // 100 출력
}
위의 코드에서처럼 네임드 아규먼트(Named Argument)를 이용한다면 모든 아규먼트들을 지정하지 않아도 인스턴스가 생성되며, 입력하고자하는 특정 아규먼트만 값을 할당하여 이용이 가능하다.
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
Widget build(BuildContext context) {
return const MaterialApp(
title: 'Color Palette',
home: HomePage(),
debugShowCheckedModeBanner: true,
theme: ThemeData(primarySwatch: ),
);
}
}
최종적으로 결론으로 돌아와 처음에 이야기를 나누었던 Object(객체), Class(클래스), Instance(인스턴스), Constructor(생성자), Named Argument(네임드 아규먼트)들을 이해하고 나서 위의 코드를 다시 한번 살펴본다면.
이젠 무언가 다른 느낌을 받을 수 있다.
결국, MaterialApp Widget(위젯)은 MaterialApp Class(클래스) 내의 생성자를 통해서 생성된 새로운 인스턴스이며.
title, home, debugShowCheckedModeBanner, theme 등 아규먼트들은 Named Argument(네임드 아규먼트)이다.
app.dart 파일에 정의된 MaterialApp 을 살펴보아도 MaterialApp Class(클래스) 내에 생성자를 통해서 각각의 속성들이 Named Argument(네임드 아규먼트)로써 정의된 것으로 이해할 수 있다.