Class의 가장 중요한 개념
OOP - Objected Oriented Programming : 객체지향 프로그래밍
Class란 무엇인가?
간단하게 비슷한 성격의 또는 기능의 변수와 함수들을 모아놓은것이라 할수있다.
직접 소스로 보면서 해보자. 일단 Class를 하나 선언해보자. (당연히 main 함수 영역 밖이다.)
void main() {
}
//Class의 모든 첫번째 글자는 반드시 대문자로 선언해야 한다.
class Color{
String name = 'red';
void sayName(){
//표현방식 1번
print('이 색은 red입니다.');
//표현방식 2번
print('이 색은 ${this.name}입니다.');
}
}
이 색은 red입니다.
하나의 변수와 단순하게 변수를 print하는 함수를 정의했다.
(표현방식 1,2를 나눈것은 참고용으로)
현재 티스토리 코드블럭 기능에서는 Dart컴파일러와 같은 하이라이트를 지원하지 않기 때문에 보이지 않지만,
실제 웹컴파일러에서는 표현방식 2번에 "this"가 선언한 class명과 색상이 동일한 것을 알수 있다.
이는 this가 현재 class를 가리키는 것을 의미하며, 현재 class안에 name이라는 변수를 지칭하는것을 뜻한다.
※ Dart 웹컴파일러는 아래 포스팅에 있으니 참고
다시 본론으로 돌아와서.
그럼 이렇게 선언한 class는 어디서 어떻게 사용할 수 있을까?
먼저 Map이나 List를 선언하여 사용하는것과 같이 마찬가지로 변수형태로 선언해야 한다.
//선언된 클래스를 변수처럼 사용하기 위해, 변수선언하듯이 선언한다.
Color color = new Color();
위 class를 선언한것을 보면 아래 Map과 List선언방식과 비슷하다는 것을 알 수 있다.
Map map = new Map();
List list = new List();
이유는 Dart에서 기본으로 제공하는 class형이기 때문이다.
이와같이 class를 인스턴스로 변환하는 것을 Instantiation이라 한다.
한글로는 인스턴스화.
위와 같이 선언된 (좌측영역) class의 변수는 하나의 인스턴스라고 부른다.
그럼 color라는 인스턴스에서 하나를 꺼내 실행해보자.
color.sayName();
print(color.name);
이 색은 red입니다.
red
위와같은 결과가 문제없이 나오고 지금까지 무리없이 따라왔다면,
기본적인 class를 선언하고, 사용하는 방법까지 익힌것이라 할수 있겠다.
또한, Map과 List도 그러하듯이, class도 여러 인스턴스를 만들수 있다.
Color color2 = new Color();
color2.sayName();
이 색은 red입니다.
red
만약, 같은방식으로 인스턴스를 생성하였지만 위 구문 기준으로
color2.sayName();을 했을때 다른 색상을 호출하고 싶다면 어떻게 해야할까?
이때 바로 Constructor라는 것을 이용할 수 있다.
Constructor는 또 무엇인가?
처음 class가 선언이 될때, 원하는 변수들을 이 class안에 집어넣을 수 있는 기능이라고 생각하면 될거같다.
그럼 Constructor는 어떻게 사용할까? 바로 소스 예제로 확인해 보자.
class Color{
String name ;
//1. 새로 추가 선언
String group ;
//Constructor - 2. 동일한 이름을 작성하여 소괄호를 열고 닫아준다.
Color(
//3. class가 인스턴스로 선언될때, 외부에서 직접 입력을 받아서 변수에 할당하고자 한다.
//4. 아래와 같이 선언하게 되면, 외부에서 값을 새로 받겠다라는 의미가 된다.
//5. 그리고 외부에서 받아온 이 name과 group는 현재class의 name과 group이라는 것을
// 가장 하단 콜론(:)뒤에 반드시 지정해준다.
String name,
String group
):this.name = name,
this.group = group
;
void sayName(){
print('이 색은 ${this.name}입니다.');
}
}
위와같이 class 생성자(Constructor) 정의가 완료된 후, 호출해보면
void main(){
Color listUp = new Color(
'blue',
'B' );
listUp.sayName();
print(listUp.name);
print(listUp.group);
}
이 색은 blue입니다.
blue
B
인자(파라미터)를 넣어 정의한 listUp이라는 인스턴스를 생성할때, class의 생성자(constructor)에서 name과 group값을
셋팅했기 때문에 위와 같은 결과를 얻을 수 있는 것이다.
※이 생성자(constructor)의 파라미터는 함수의 파라미터와 같은 역할을 한다.
※직접 class를 생성해보고, 여러번 돌려보면서 체화하는것이 중요하다.
그렇다면 생성자(constructor)에 네임드 파라미터를 넣을 수 있을까?
class Color{
String name ;
String group ;
//소괄호 안에 중괄호를 열어서 선언.
Color({
String name,
String group
}
):this.name = name,
this.group = group;
void sayName(){
print('이 색은 ${this.name}입니다.');
}
}
생성자(constructor)의 소괄호 안에 중괄호를 열어서 선언한다.
다음 main 함수에서 호출시가 달라지는데, 네임드 파라미터의 특징답게 변수명을 지정하여 할당한다.
물론, 네임드 파라미터의 특성답게 순서가 달라져도 상관없다.
void main(){
Color listUp = new Color(
group : 'B',
name : 'blue'
);
listUp.sayName();
print(listUp.name);
print(listUp.group);
}
이 색은 blue입니다.
blue
B
이와 같이 같은 결과값을 얻을 수 있다.
생성자(constructor)에 대해 한가지를 더 다뤄보자면,
일반적으로 JAVA처럼 OOP를 자주 쓰는 언어에서는 constructor 오버로딩이라는 개념이 존재하는데
Dart에서는 다른 이름이 존재한다. 바로, 네임드 컨스트럭터(=생성자)라 한다.
다시 class로 돌아와서 추가로 생성자를 추가해보자.
class Color{
String name ;
String group ;
//소괄호 안에 중괄호를 열어서 선언.
Color({
String name,
String group
}
):this.name = name,
this.group = group;
//1. Map값을 받아서 이 class를 생성할 수 있는 또 하나의 생성자를 만들어보자
//2. '클래스명.적당한이름' 의 형태로 짓는다.
//3. Map값을 받아서 Key값이 name인것은 이 클래스의 name으로,
//4. Key값이 group인것은 이 클래스의 group으로 넣어줄 수 있도록 지정해준다.
Color.fromMap(
Map input
) : this.name = input['name'],
this.group = input['group']
;
void sayName(){
print('이 색은 ${this.name}입니다.');
}
}
위 코멘트 1~4번에서도 작성했듯이, class가 인스턴스화 될때, 방식에 따라 다르게 선언하여 생성할 수 있다.
(※ fromMap은 Map값을 받아서 인스턴스화 시키기 위해 지은 적당한 이름이지 함수명 같은것이 아님)
위와같이 정의하면 Map형태로 넘어온 값은 인스턴스화 될때, Key값이 name인 것의 value를 class의 name으로
Key값이 group인 것의 value를 class의 group으로 지정할 수 있다.
void main(){
Color listUp = new Color(
group : 'B',
name : 'blue'
);
listUp.sayName();
print(listUp.name);
print(listUp.group);
Color frMap = new Color.fromMap({
'name' : 'pink',
'group' : 'P'
});
frMap.sayName();
print(frMap.name);
print(frMap.group);
}
이 색은 blue입니다.
blue
B
이 색은 pink입니다.
pink
P
이렇듯 위 2개의 예제를 통해, 한 class안에서 여러개의 다양한 방식의 생성자를 사용할 수 있게된다.
또한 class를 인스턴스화 할수 있는 방법이 여러가지라는 것을 의미한다.
그런데, class를 인스턴스화 할때 생성자의 값을 초기화(기본값)후, 변경되지 않게 하려면 어떻게 할까?
void main(){
Color frMap = new Color.fromMap({
'name' : 'pink',
'group' : 'P'
});
frMap.name = 'purple';
print(frMap.name);
}
위와같이 name의 값을 분명히 pink로 초기화 했는데, 인스턴스화 후 purple로 변경 후에 값을 출력하면 어떻게 될까?
당연히 name은 purple로 변경되어 뜬다.
물론 값을 변경할 일이 있을수 있지만, 그렇지 않고 변경을 원치 않는 경우도 있다.
그럴땐, final을 이용한다.
class Color{
final String name ;
final String group ;
Color({
String name,
String group
}
):this.name = name,
this.group = group;
Color.fromMap(
Map input
) : this.name = input['name'],
this.group = input['group']
;
void sayName(){
print('이 색은 ${this.name}입니다.');
}
}
위와 같이 class에 선언된 name과 group변수에 final을 붙여서 반드시 변하지 않는 값임을 명시해준다.
final로 선언되면 인스턴스화 당시 값 초기화 후, 이후엔 절대 변경할 수 없다.
하나 주의할 점은 final로 지정된 이상 생성자에서는 반드시 값을 바인딩해주어야 한다.
(:this.name = name ) <- final로 선언된 변수가 생성자로 부터 연결되는 값이 없다면 오류가 발생한다.
초기화 후, 절대 변경이 되서는 안되는 값이므로 연결이 안될 수가 없다는 것을 의미하기 때문이다.
굉장히 유용하므로 final도 잘 기억해 두자.
앞 부분 스터디들은 크게 지루하고 재미없었지만, class로 진입하고 나서부터는 다시 들어도 재밌다.
코드팩토리님의 Dart 기초강의를 듣고싶다면 아래 포스팅 참고!
오늘 class 스터디 완료!!