flutter를 위한 dart 기본 문법 (2) - OOP
직전 포스팅에서 dart 기본 문법에 대해서 알아보았는데요, 이번에는 dart에서의 oop 개념에 대해서 알아보겠습니다.
필자는 깊진 않지만 여러 프로그래밍 언어에 대한 경험(컴공)이 있기 때문에 순전히 필자의 기준으로 작성했으니 이 포스트는 프로그래밍 언어를 처음 배우시는 분에겐 맞지 않을 수 있으니 유의!!!
다른 언어를 배워본 경험이 있으신 분들은 가볍게 보시면 dart 문법 금방 아실 거라고 생각합니다.
**음슴체**
클래스 - 설계도
인스턴스 - 설계도로 인해 만들어진 무언가(n개)
클래스 기본(생성자)
void main() {
Idol blackPink = Idol(
'블랙핑크',
['지수', '제니', '리사', '로제'],
);
print(blackPink.name);
print(blackPink.members);
blackPink.sayHello();
blackPink.introduce();
Idol bts = Idol(
'bts',
['RM', '진', '슈가', '제이홉', '지민', '뷔', '정국'],
);
Idol bts2 = Idol.fromList([
['RM', '진', '슈가', '제이홉', '지민', '뷔', '정국'],
'bts',
]
);
}
class Idol {
final String name; // final : immutable 프로그래밍 지향
final List<String> members;
// Idol(String name, List<String> members) // constructor(생성자) - 정석 버전
// : this.name = name,
// this.members = members;
Idol(this.name, this.members); // constructor(생성자) - 간결한 버전
Idol.fromList(List values)
: this.members = values[0],
this.name = values[1];
void sayHello() {
print("안녕하세요 ${this.name}입니다.");
}
void introduce() {
print('저희 멤버는 ${this.members}가 있습니다.');
}
}
const와 인스턴스
인스턴스에 const를 쓰면 값을 값을 가지는 두 개의 인스턴스가 하나의 인스턴스가 된다.
Idol blackPink = Idol(
'블랙핑크',
['지수', '제니', '리사', '로제'],
);
Idol blackPink2 = Idol(
'블랙핑크',
['지수', '제니', '리사', '로제'],
);
print(blackPink == blackPink2) ---> false
Idol blackPink = const Idol(
'블랙핑크',
['지수', '제니', '리사', '로제'],
);
Idol blackPink2 = const Idol(
'블랙핑크',
['지수', '제니', '리사', '로제'],
);
print(blackPink == blackPink2) ---> true
getter/setter
데이터를 가져올 때 / 데이터를 설정할 때
void main() {
Idol blackPink = Idol(
'블랙핑크',
['지수', '제니', '리사', '로제'],
);
Idol bts = Idol.fromList([
['RM', '진', '슈가', '제이홉', '지민', '뷔', '정국'],
'bts',
]
);
// using getter
print(blackPink.firstMember);
print(bts.firstMember);
// using setter
blackPink.firstMember = '아무개';
bts.firstMember = '아이언맨';
print(blackPink.firstMember);
print(bts.firstMember);
}
class Idol {
final String name; // final : immutable 프로그래밍 지향
final List<String> members;
Idol(this.name, this.members); // constructor(생성자) - 간결한 버전
// getter
String get firstMember{
return this.members[0];
}
// setter
set firstMember(String name){
this.members[0] = name;
}
function을 사용해서 반환해도 되지만 왜 getter 사용할까? -> 간단한 데이터 가공
function - 로직이 들어가는 부분 (뉘앙스 차이)
setter는 잘 사용 x -> immutable 프로그래밍에 위배, final을 쓰면 해당 값을 바꾸지 못하는데 setter는 그것을 바꾸려고 하는 성질(list는 특별해서 list 내의 value들은 변경 가능)
private
private은 변수 왼쪽 '_' 붙이면 됨.
ex. _Idole, _name, _members ...
왜? 다른 파일에서 해당 파일의 클래스나 함수를 참조하지 못하게 하기 위해.
상속(inheritance)
상속을 받으면 부모 클래스의 모든 속성을 자식 클래스가 부여받는다
자식 클래스의 함수는 부모 클래스에 영향 미치지 않는다.
같은 자식 클래스라도 속성을 공유하지 않는다.
void main() {
print('-------- Idol ----------');
Idol apink = Idol(name: '에이핑크', membersCount: 5);
apink.sayName();
apink.sayMembersCount();
print('-------- Boy Group ----------');
BoyGroup bts = BoyGroup('BTS', 7);
bts.sayName();
bts.sayMembersCount();
bts.sayMale();
print('-------- Girl Group ----------');
GirlGroup redVelvet = GirlGroup('Red Velvet', 5);
redVelvet.sayName();
redVelvet.sayMembersCount();
redVelvet.sayFemale();
}
class Idol {
String name;
int membersCount;
Idol({
required this.name,
required this.membersCount,
});
void sayName() {
print('저는 ${this.name}입니다.');
}
void sayMembersCount() {
print('${this.name}은 ${this.membersCount}명의 멤버가 있습니다.');
}
}
class BoyGroup extends Idol {
BoyGroup(
String name,
int membersCount,
) : super(name: name, membersCount: membersCount);
void sayMale(){
print('저는 남자 아이돌입니다.');
}
}
class GirlGroup extends Idol {
GirlGroup(
String name,
int membersCount,
): super(name:name, membersCount: membersCount);
void sayFemale(){
print('저는 여자 아이돌입니다.');
}
}
부모 클래스의 인스턴스와 자식 클래스의 인스턴스 타입 비교
부모 클래스의 인스턴스는 자식 클래스가 될 수 없다.
하지만 자식 클래스의 인스턴스는 부모 클래스 또는 자기 자신이 될 수 있다. (같은 자식 클래스는 서로가 될 수 없다.)
print('--------------- Type Comparison ----------------');
print(apink is Idol); -> true
print(apink is BoyGroup); -> false
print(apink is GirlGroup); -> false
print('--------------- Type Comparison 2 ----------------');
print(bts is Idol); -> true
print(bts is BoyGroup); -> true
print(bts is GirlGroup); -> false
print('--------------- Type Comparison 3 ----------------');
print(redVelvet is Idol); -> true
print(redVelvet is BoyGroup); -> false
print(redVelvet is GirlGroup); -> true
override
덮어쓰다 (우선시하다)
method - function ( class 내부에 있는 함수)
void main() {
TimesTwo tt = TimesTwo(2);
print(tt.calculate()); -> 4
TimesFour tf = TimesFour(2);
print(tf.calculate()); -> 8
}
class TimesTwo{
final int number;
TimesTwo(
this.number,
);
// method
int calculate(){
return number * 2;
}
}
class TimesFour extends TimesTwo{
TimesFour(
int number,
): super(number);
// @override
// int calculate(){
// return super.number * 4; // super 삭제해도 무방
// }
@override
int calculate(){
return super.calculate() * 2;
}
}
static
static은 instance에 귀속되지 않고 class에 귀속된다.
void main() {
Employee seulgi = Employee('슬기');
Employee chorong = Employee('초롱');
// 각 인스턴스에 귀속
seulgi.name = '아무개';
seulgi.printNameAndBuilding();
chorong.printNameAndBuilding();
// 해당 클래스에 귀속되기 때문에, 모든 인스턴스의 building은 다원빌리지가 된다. (static 변수)
Employee.building = '다원빌리지';
seulgi.printNameAndBuilding();
chorong.printNameAndBuilding();
// static method
Employee.printBuilding();
}
class Employee {
static String? building;
String name;
Employee(
this.name,
);
void printNameAndBuilding(){
print('제 이름은 $name입니다. $building 건물에서 근무하고 있습니다.');
}
static void printBuilding(){
print('저는 $building 건물에서 근무중입니다.');
}
}
인스턴스에 귀속된다 -> 인스턴스를 만들고 난 뒤 실행하거나 .(접근)하여 값을 변경하는 것
클래스에 귀속된다 -> 클래스에 직접적으로 실행하거나 .(접근)하여 값을 변경하는 것
interface
상속이 속성과 기능을 물려주기 위한 것이라면 인터페이스는 어떤 특수한 구조를 강제하는 것, 타입 비교는 상속과 같다.
void main() {
BoyGroup bts = BoyGroup('BTS');
GirlGroup redVelvet = GirlGroup('레드벨벳');
bts.sayNmae();
redVelvet.sayNmae();
}
abstract class IdolInterface { // abstract - 인스턴스로 만들지 못함, 함수의 body 삭제 가능
String name;
IdolInterface(this.name);
void sayNmae();
}
class BoyGroup implements IdolInterface{
String name;
BoyGroup(this.name);
void sayNmae() {
print('제 이름은 $name입니다.');
}
}
class GirlGroup implements IdolInterface{
String name;
GirlGroup(this.name);
void sayNmae() {
print('제 이름은 $name입니다.');
}
}
generic
타입을 외부에서 받을 때 사용
void main() {
Lecture<String, String> lecture1 = Lecture('123', 'Lecture1');
lecture1.printIdType();
Lecture<int, String> lecture2 = Lecture(123, 'Lecture2');
lecture2.printIdType();
}
class Lecture<T, X> {
final T id;
final X name;
Lecture(this.id, this.name);
void printIdType(){
print(id.runtimeType);
}
}
Object Oriented Programming - OOP
모든 클래스의 최상위 부모는 Object, 그래서 객체 지향 프로그램(Object Oriented Programming - OOP)
ex. class Test extends Object{} --> extends Object 생략
이번 포스팅은 dart oop에 대해 알아보았습니다.
다음 포스팅은 functional programming에 대해 알아보겠습니다. 감사합니다.