포스팅 환경
- M1 Mac OS Monterey 12.6
- Dart 2.18.2
개요
Dart 는 실제 세계를 반영한 객체 지향 프로그래밍 언어입니다.
따라서 클래스, 상속, 다형성 등을 이용해 코드를 작성할 수 있습니다.
이번 포스팅에서는 Dart 에서는 클래서, 상속, 추상 클래스 등을
어떻게 사용하는지 알아보려 합니다.
코드를 실행해서 테스트하고 싶은신 분들은 아래 사이트에서
실행할 수 있습니다 :)
클래스
Dart 에서도 Java, Kotlin 처럼 class 라는 것이 존재 합니다.
다음 코드는 클래스를 정의하는 코드입니다.
name 과 age 가 non null 이라서 반드시 초기 값을 넣어주도록 명시한 것을 알 수 있습니다.
class Animal {
String name = "Cat";
int age = 2;
}
초기 값을 넣고 싶지 않다면 nullable 하게도 만들 수 있습니다.
class Animal {
String? name;
int? age;
}
Animal 타입의 클래스를 인스턴화 하는 방법을 보겠습니다.
new 키워드를 사용해도 되고, 사용하지 않고도 인스턴스를 생성할 수 있습니다.
void main() {
var animal = Animal();
var animal = new Animal();
}
다음은 프로퍼티를 접근하는 방법을 보겠습니다.
여타 다른 언어들 처럼 변수명 뒤에 . 연산자를 입력해 생성한 객체의 프로퍼티에 접근할 수 있습니다.
void main() {
var animal = Animal();
print(animal.name);
print(animal.age);
}
class Animal {
String name = "Cat";
int age = 2;
}
/* 결과 */
Cat
2
당연하게도 클래스 내에 함수를 정의 할 수 있고 이를 접근할 수도 있습니다.
void main() {
var animal = Animal();
print(animal.name);
print(animal.age);
animal.addAge(1);
print(animal.age);
}
class Animal {
String name = "Cat";
int age = 2;
void addAge(int addAge) {
age += addAge;
}
}
/* 결과 */
Cat
2
3
접근제한자
프로퍼티와 함수에 대한 접근을 제한하는 방법을 알아보겠습니다.
프로퍼티와 함수 모두 이름 앞에 _ 키워드를 명시하면 priavte 되고 접근할 수 없게 됩니다.
이 private 한 프로퍼티를 접근 가능한 허용범위는 같은 dart 파일 내에서만 가능합니다.
코드를 살펴보겠습니다.
프로퍼티 제한
void main() {
var animal = Animal();
print(animal.name); /* 컴파일 에러 발생 */
print(animal.age); /* 컴파일 에러 발생 */
animal.addAge(1);
print(animal.age); /* 컴파일 에러 발생 */
}
class Animal {
String _name = "Cat";
int _age = 2;
void addAge(int addAge) {
age += addAge;
}
}
함수 접근 제한
함수 역시 앞서 본 프로퍼티 처럼 _ 를 붙여 접근을 private 하게 만들어 제한 할 수 있습니다.
void main() {
var animal = Animal();
print(animal.name);
print(animal.age);
animal.addAge(1); /* 컴파일 에러 발생 */
print(animal.age);
}
class Animal {
String name = "Cat";
int age = 2;
void _addAge(int addAge) {
age += addAge;
}
}
생성자
생성자는 클래스를 인스턴스로 생성할 수 있도록 방법을 제공하는 함수라고 할 수 있습니다.
Dart 는 기본 생성자를 제공하는데 클래스명과 같은 이름의 함수입니다.
Java, Kotlin 처럼 기본 생성자를 생략하고 정의하여도 기본 생성자로
인스턴스 생성이 가능하다는 것을 알 수 있습니다.
class Animal {
/* 기본 생성자가 존재하지 않는다. */
String name = "Cat";
int age = 2;
}
void main() {
/* 기본 생성자로 생성 가능 */
var animal = Animal();
}
Getter 와 Setter
겟터와 셋터는 인스턴스의 프로퍼티에 접근하는 방법을 제공하는 곳에 주로 사용됩니다.
만약 프로퍼티를 Private 로 만들고 직접 접근하는 것을 막고 싶을 때 겟터와 셋터를 이용해서
프로퍼티에 접근하는 또 다른 방법을 제공할 수 도 있습니다.
겟터와 셋터의 기본적인 문법을 살펴보겠습니다.
겟터는 아래 형식으로 정의할 수 있습니다.
[타입] get [이름] => [반환 값];
셋터는 아래 형식으로 정의 할 수 있습니다.
set [함수명](파라미터) => 프로퍼티 값 = 파라미터;
Animal 클래스를 겟터와 셋터를 정의하도록 고쳐보도록 하겠습니다.
class Animal {
String _name = "Cat";
int _age = 2;
String get name => _name;
set name(String value) => _name = value;
int get age => _age;
set age(int value) => _age = value;
}
get 뒤에 _name 과 동일한 name 이라고 정의해주었는데요.
꼭 name 이라고 정의하지 않아도 됩니다.
set 뒤에 name 이라고 정의하였지만 이는 어떤 프로퍼티를 초기화 해주는 셋터인지
헷갈리지 않기 위해서 한것이지 꼭 name 이라는 이름으로 정의 할 필요는 없습니다.
그리고 get, set 를 살펴보면 => 로 람다식으로 사용하는 것을 알 수 있는데요
여기서 알 수 있듯이 get, set 는 함수임을 알 수 있습니다.
따라서 람다식이 아닌 단순 함수 형태로도 정의하여 사용 할 수 있습니다.
class Animal {
String _name = "Cat";
int _age = 2;
String get name {
return _name;
}
set name(String value) {
_name = value;
}
int get age {
return _age;
}
set age(int value) {
_age = value;
}
}
이제 예제 코드를 테스트 해보도록 하겠습니다.
겟터와 셋터가 아닌 프로퍼티에 직접적으로 접근하려고 하면
컴파일 에러가 발생하는 것을 알 수 있습니다.
void main() {
var animal = Animal();
print(animal.age);
print(animal.name);
print(animal._age); /* 컴파일 에러 발생 */
print(animal._name); /* 컴파일 에러 발생 */
}
class Animal {
String _name = "Cat";
int _age = 2;
String get name => _name;
set name(String value) => _name = value;
int get age => _age;
set age(int value) => _age = value;
}
제대로 테스트 해볼려면 main.dart, animal.dart 라는 다트파일로 분리해야
_을 사용하여 private 하게 접근이 막혀서 컴파일 에러가 발생하는 것을 볼 수 있습니다.
상속
Dart 도 Java, Kotlin 처럼 상속이 가능합니다.
객체지향을 지원하는 언어이기 때문입니다.
상속을 하는 문법은 Java 와 거의 동일하다고 할 수 있습니다.
Java 처럼 extends 키워드를 사용하여 상속 받고자 하는 클래스를 정의할 수 있습니다.
Cat 이라는 class 가 Animal class 를 상속을 하는 예제코드를 살펴보도록 하겠습니다.
void main() {
var cat = Cat(
"삼색이",
"Cat",
3
);
print(cat.info());
}
class Animal {
String _type = "";
int _age = -1;
String get type => _type;
set type(String value) => _type = value;
int get age => _age;
set age(int value) => _age = value;
info() {
print("type: $_type, age: $_age");
}
}
class Cat extends Animal {
Cat(String name, String type, int age) {
super._age = age;
super._type = type;
_name = name;
}
String _name = "";
String get type => _type;
set type(String value) => _type = value;
}
/* 결과 */
// type: Cat, age: 3
Cat 클래스는 Animal 클래스를 상속 받았기 때문에 info 함수를 호출 할 수 있습니다.
info 함수는 또한 재정의가 가능합니다.
class Cat extends Animal {
...
@override
info() {
print("name: $name, type: $type, age: $age");
}
}
/* 결과 */
// name: 삼색이, type: Cat, age: 3
추상클래스
Dart 에서도 Java, Kotlin 처럼 추상클래스를 정의 할 수 있습니다.
추상클래스는 그대로 인스턴스화 할 수 없으며 다른 클래스에서
상속하여 기능을 완성하는 상속 재료로 사용됩니다.
이 때 대상 클래스에는 마찬가지로 extends 키워드를 사용하여 상속 받을 수 있습니다.
abstract class Animal {
void info();
}
일반 클래스를 상속 받는 것과 똑같이 함수 재정의가 가능하지만
다른 점은 추상클래스에 정의된 함수는 필수적으로 재정의하여야 하는 것이 차이점 입니다.
class Cat extends Animal {
...
@override
info() {
print("name: $name, type: $type, age: $age");
}
}
/* 결과 */
// name: 삼색이, type: Cat, age: 3
마무리
여기까지 Dart 언어에서의 기본적인 객체지향 문법을 살펴보았습니다.
이상으로 포스팅을 마치겠습니다.
감사합니다. :)
'Develop > Flutter' 카테고리의 다른 글
[Dart] 배우기 - 4. 컬렉션 (0) | 2022.10.26 |
---|---|
[Dart] 배우기 - 3. 분기와 반복 (0) | 2022.10.26 |
[Dart] 배우기 - 2. 함수 정의와 호출 (0) | 2022.10.25 |
[Dart] 배우기 - 1. 기본 문법 (0) | 2022.10.24 |
[Flutter] - 앱 실행 도중 멈춤 현상(IOS, 신뢰하지 않는 개발자) (0) | 2022.10.24 |