모음/[코드팩토리의 플러터 프로그래밍]

[코드팩토리의 플러터 프로그래밍] 2장. 다트 객체지향 프로그래밍

ttoance 2024. 7. 14. 22:56

 

 

1. 객체지향 프로그래밍의 필요성 

1) 모든 코드를 main()함수에서 작성하면 코드 정리가 안돼 장애물이 됨.

2) 변수와 메서드를 특정 클래스에 종속되게 코딩할 수 있음. > 코드 관리가 용이해짐

 

2. 클래스와 인스턴스 

1) 클래스 : 일종의 설계도로 데이터가 보유할 속성과 기능을 정의하는 자료구조 

2) 인스턴스 : 클래스를 이용해서 객체를 선언하면 해당 객체를 인스턴스라고 부름 

 

3. 클래스의 생성자 

1) 생성자 : 클래스의 인스턴스를 생성하는 메서드 

2) 네임드 생성자 : 클래스를 생성하는 여러 방법을 명시하고 싶을 때 사용 

class Idol {
  // 생성자에서 입력받는 변수들은 일반적으로 final 키워드 사용 
  final String name;
  final int membersCount;
  
  // 생성자 선언 : 클래스와 같은 이름이어야 함.
  Idol(String name, int membersCount) : 
    this.name = name,
    this.membersCount = membersCount;
  
  // 네임드 생성자 : {클래스명.네임드 생성자명} 형식
  Idol.fromMap(Map<String, dynamic> map) :
    this.name = map['name'],
    this.membersCount = map['memberCount'];
  
  void sayName() {
    print('저는 ${this.name}입니다. 멤버는 ${this.membersCount} 명입니다. ');
  }
}

void main() {
  // 기본 생성자 사용 
  Idol blackPink = Idol('블랙핑크', 4);
  blackPink.sayName();
  
  // fromMap 이라는 네임드 생성자 사용 
  Idol bts = Idol.fromMap({
    'name' : 'bts',
    'memberCount' : 7
  });
  bts.sayName();
}

 

실행화면 >>

 

4. 프라이빗 변수 

ㄴ 일반적으로 프라이빗 변수는 클래스 내부에서만 사용하는 변수를 칭하지만, 

다트 언어에서는 같은 파일에서만 접근 가능한 변수임. 

class Idol {
  // _ 로 변수명 시작하면 프라이빗 변수 선언 
  String _name;
  
  Idol(this._name);
}

void main() {
  Idol blackPink = Idol('블랙핑크');
 
  // 같은 파일에서는 변수명을 _기호로 시작해 접근 가능
  // 다른 파일에서는 접근 불가능
  print(blackPink._name);
}

실행화면 >>

 

5. 게터/세터 

class Idol {
  // _ 로 변수명 시작하면 프라이빗 변수 선언 
  String _name = '';
  
  // get 키워드 사용해 게터임을 명시 
  // 게터는 매개변수를 받지 않음
  String get name {
    return this._name;
  }
  
  // set 키워드 사용해 세터임을 명시 
  // 매개변수로 값 하나 받을 수 있음
  set name (String name) {
    this._name = name; 
  }
}

void main() {
  Idol blackPink = Idol();
  
  blackPink.name = '에이핑크'; // 세터 
  print(blackPink._name); // 게터 
}

 

실행화면 >>

 

 

6. 상속 

1) 어떤 클래스의 기능을 다른 클래스가 사용할 수 있게 하는 기법

2) 자식 클래스는 부모 클래스의 모든 기능을 상속받는다. 

3) super 키워드는 상속한 부모 클래스를 지칭한다. 

class Idol {
  // 생성자에서 입력받는 변수들은 일반적으로 final 키워드 사용 
  final String name;
  final int membersCount;
  
  // 생성자 선언 : 클래스와 같은 이름이어야 함.
  Idol(String name, int membersCount) : 
    this.name = name,
    this.membersCount = membersCount;
  
  void sayName() {
    print('저는 ${this.name}입니다. 멤버는 ${this.membersCount} 명입니다. ');
  }
}

class BoyGroup extends Idol {
  BoyGroup(
    String name,
    int membersCount,
  ) : super(
    name,
    membersCount
  );
}

void main() {
  // 기본 생성자 사용 
  Idol bts = BoyGroup('bts', 7);
  bts.sayName();
}

 

실행화면 >>

 

7. 인터페이스

1) 공통으로 필요한 기능 정의만 해두는 기능 

2) 상속과의 차이점

- 상속은 단 하나의 클래스만 할 수 있지만, 인터페이스는 제한이 없음 

- 상속받을 때는 재엉의할 필요 없지만, 인터페이스는 반드시 재정의해줘야 함. 

class Idol {
  // 생성자에서 입력받는 변수들은 일반적으로 final 키워드 사용 
  final String name;
  final int membersCount;
  
  // 생성자 선언 : 클래스와 같은 이름이어야 함.
  Idol(String name, int membersCount) : 
    this.name = name,
    this.membersCount = membersCount;
  
  void sayName() {
    print('저는 ${this.name}입니다. ');
  }
  
  void sayMembersCount() {
    print('${this.name} 멤버는 ${this.membersCount} 명 입니다. ');
  }
}

class GirlGroup implements Idol {
  final String name;
  final int membersCount; 
  
  GirlGroup(
    this.name,
    this.membersCount,
  );
  
   void sayName() {
    print('저는 여자아이돌 ${this.name}입니다. ');
  }
  
   void sayMembersCount() {
    print('${this.name} 멤버는 ${this.membersCount} 명 입니다. ');
  }

}

void main() {
  // 기본 생성자 사용 
  Idol blackPink = GirlGroup('블랙핑크', 4);
  
  blackPink.sayName();
  blackPink.sayMembersCount();
}

 

실행화면 >>

 

8. 오버라이드

ㄴ부모 클래스 또는 인터페이스에 정의된 메서드 재정의할때 사용 

  @override
   void sayMembersCount() {
    print('${this.name} 멤버는 ${this.membersCount} 명 입니다. ');
  }

 

9.믹스인 

ㄴ특정 클래스에 원하는 기능들만 골라 넣을 수 있는 기능 

class Idol {
  // 생성자에서 입력받는 변수들은 일반적으로 final 키워드 사용 
  final String name;
  final int membersCount;
  
  // 생성자 선언 : 클래스와 같은 이름이어야 함.
  Idol(String name, int membersCount) : 
    this.name = name,
    this.membersCount = membersCount;
  
  void sayName() {
    print('저는 ${this.name}입니다. ');
  }
  
  void sayMembersCount() {
    print('${this.name} 멤버는 ${this.membersCount} 명 입니다. ');
  }
}

mixin IdolSingMixin on Idol{
  void sing() {
    print('${this.name}이 노래를 부릅니다.');
  }
}

// 믹스인 적용 시 with 키워드 사용 
class BoyGroup extends Idol with IdolSingMixin{
  BoyGroup(
    super.name,
    super.membersCount
  );
  
  void sayMale() {
    print('저는 남자 아이돌 입니다.');
  }
}

void main() {
  BoyGroup bts = BoyGroup('bts', 7);
  
  // 믹스인 정의된 함수 사용 가능
  bts.sing();
}

 

실행화면 >>

 

10. 추상

1) 상속이나 인터페이스로 사용하는데 필요한 속성만 정의하고 인스턴스할수 없도록 하는 기능 

2) 추상 클래스는 추상 메서드를 선언할 수 없으며, 함수의 반환 타입, 이름, 매개변수만 정의하고 삼수 바디의 선언을 자식 클래스에서 필수로 정의하도록 강제 

abstract class Idol {
  // 생성자에서 입력받는 변수들은 일반적으로 final 키워드 사용 
  final String name;
  final int membersCount;
  
  // 생성자 선언 : 클래스와 같은 이름이어야 함.
  Idol(this.name, this.membersCount);
  
  void sayName(); // 추상 메서드 선언 
  void sayMembersCount(); // 추상 메서드 선언 
}


class GirlGroup implements Idol {
  final String name;
  final int membersCount; 
  
  GirlGroup(
    this.name,
    this.membersCount,
  );
  
   void sayName() {
    print('저는 여자아이돌 ${this.name}입니다. ');
  }
  
   void sayMembersCount() {
    print('${this.name} 멤버는 ${this.membersCount} 명 입니다. ');
  }

}

void main() {
  // 기본 생성자 사용 
  Idol blackPink = GirlGroup('블랙핑크', 4);
  
  blackPink.sayName();
  blackPink.sayMembersCount();
}

 

실행화면 >>

 

11. 제네릭 

ㄴ 클래스나 함수의 정의를 선언할때가 아니라 인스턴스화하거나 실행할 때로 미룸 

// 인스턴스화할때 입력받을 타입 T로 지정 
class Cache<T> {
  
  final T data;
  
  Cache({
    required this.data,
  });
}

void main() {
  // T의 타입을 List<int>으로 입력
  final cache = Cache<List<int>> (
    data: [1, 2, 3]
  );
  
  print(cache.data.reduce((value, element) => value + element));
}

 

실행화면 >>

 

12. 스태틱

ㄴ 클래스 자체에 귀속시킴 

class Counter {
  static int i = 0; 
  
  Counter() {
    i++;
    print(i);
  }
}

void main() {
  Counter count1 = Counter();
  Counter count2 = Counter();
  Counter count3 = Counter();
}

 

실행화면 >>

 

13. 캐스캐이드 연산자

ㄴ 해당 인스턴스의 속성이나 멤버 함수를 연속해서 사용하는 기능  

class Idol {
  // 생성자에서 입력받는 변수들은 일반적으로 final 키워드 사용 
  final String name;
  final int membersCount;
  
  // 생성자 선언 : 클래스와 같은 이름이어야 함.
  Idol(String name, int membersCount) : 
    this.name = name,
    this.membersCount = membersCount;
  
  void sayName() {
    print('저는 ${this.name}입니다. ');
  }
  
  void sayMembersCount() {
    print('${this.name} 멤버는 ${this.membersCount} 명 입니다. ');
  }
}

class GirlGroup implements Idol {
  final String name;
  final int membersCount; 
  
  GirlGroup(
    this.name,
    this.membersCount,
  );
  
   void sayName() {
    print('저는 여자아이돌 ${this.name}입니다. ');
  }
  
   void sayMembersCount() {
    print('${this.name} 멤버는 ${this.membersCount} 명 입니다. ');
  }

}

void main() {
  // 기본 생성자 사용 
  // Idol blackPink = GirlGroup('블랙핑크', 4);
  // blackPink.sayName();
  // blackPink.sayMembersCount();
  
  // cascade operator 사용하면 메서드 연속적으로 실행할 수 있음
  Idol blackPink = Idol('블랙핑크', 4)
     ..sayName()
    ..sayMembersCount();
}

 

실행화면 >>

반응형