4 분 소요

Dart 객체 지향

객체 지향은 프로그램을 명령어의 집합으로 보는 시각에서 벗어나 독립된 객체들의 모임으로 보는 프로그래밍 패러다임이다. dart 또한 객체지향 언어로 다른 언어들과 유사한(constructor, getter/setter …) 문법들을 지원하고 있으며 dart만의 특이점(mixin)을 지니는 문법 또한 존재한다.

Class 와 Instance

class and instance

객체지향 언어로서 Dart의 특징

  • 모든 변수는 객체이다.
  • Object 클래스는 모든 class의 부모 객체이다.

접근 제한자

  • Dart는 접근 제한자가 따로없음
  • 변수명 앞에 underscore(_)를 붙여 private 변수로 지정
  • private변수는 외부 파일에서 접근이 불가능 하지만 동일한 파일 내에선 접근 가능
class Idol{
  String _name; // 접근제한자
  int membersCount;
  Idol(this._name, this.membersCount);
}

getter/setter

class Idol{
  String _name;
  int membersCount;
  Idol(this._name, this.membersCount);
   
  String get myname{
    return this._name;
  }
  set myname(String n){
    this._name = n;
  }
}

void main() {
  Idol hot = Idol("Hot", 5);
  print(hot.myname);  // Hot
  
  hot.myname = "BTS";
  print(hot.myname);  // BTS
}

  • 멤버 변수에 직접 접근 하는것보다 getter/setter를 사용하면 코딩 실수를 줄일 수 있다.
  • getter/setter를 메소드로 만드는 다른 언어들과 달리 get, set 키워드를 자체지원
  • 외부에서 import한 private변수에도 getter, setter를 접근가능

Constructor

Default Constructor

Dart는 field 초기화를 좀 더 간소화 하기 위한 자체 문법이 존재한다.

class Idol{
  String name;
  int membersCount;
  Idol(String name, int membersCount):
    this.name = name,
    this.membersCount = membersCount;
  
   void hello() {
    print("Hello I'm $name we have $membersCount members");
  }
}

위 코드는 아래와 같이 축약이 가능

class Idol{
  String name;
  int membersCount;
  Idol(this.name, this.membersCount);
  
  void hello() {
    print("Hello I'm $name we have $membersCount members");
  }
}

Named Constructor

Named Constructor는 Default constructor과는 별개로 생성이 가능

class Idol {
  String name;
  int membersCount;
  Idol(this.name, this.membersCount); // default constructor
  Idol.fromList(List values)  // name constructor
      : this.name = values[0],
        this.membersCount = values[1];

  void hello() {
    print("Hello I'm $name we have $membersCount members");
  }
}

void main() {
  List btsInfo = ["BTS", 7];
  Idol bts = Idol.fromList(btsInfo);
  bts.hello();
}

Const Constructor

field 가 모두 final로 선언되었기 때문에 field 값을 바꿀 수 없다.

class Idol {
  final String name;
  final int membersCount;
  const Idol(this.name, this.membersCount);
  Idol.fromList(List values)
    :this.name = values[0],
     this.membersCount = values[1];
   void hello() {
    print("Hello I'm $name we have $membersCount members");
  }
}
void main() {
  Idol idol1 = const Idol("Idol", 5);
  Idol idol2 = const Idol("Idol", 5);
  Idol idol3 = Idol("Idol", 5);
  Idol idol4 = Idol("Idol", 5);
  print(idol1 == idol2);
  print(idol3 == idol4);
}

const constructor로 생성된 동일한 내용의 constructor은 같은 instance로 취급

Dart 상속

Dart는 상속은 Java의 그것과 유사하다.

extends 키워드로 상속을 하고 super키워드로 부모 클래스에 접근한다.

interface

  • dart에서 interface는 클래스를 이용하여 선언

  • 사용할 땐 implements를 이용

  • 클래스 형태를 맞추도록 강제하는 역할

class Idol {
  final String name;
  final int membersCount;
  const Idol(this.name, this.membersCount);
   void hello() {} //형태만 강제
}

class BoyGroup implements Idol {
  String name;
  int membersCount;
  BoyGroup(this.name, this.membersCount);
  void hello(){
    print("My name is $name we have $membersCount boys");
  }
}

class GirlGroup implements Idol {
  String name;
  int membersCount;
  GirlGroup(this.name, this.membersCount);
  void hello(){
    print("My name is $name we have $membersCount girls");
  }
}
void main() {
  BoyGroup bg = BoyGroup("BTS", 5);
  BoyGroup gg = BoyGroup("Nespa", 6);
  
  Idol idol = Idol("boy", 7); // Bad
}

interface를 인스턴스화 하는것은 바람직하지 않다.

abstract

abstract class Idol {
  final String name;
  final int membersCount;
  const Idol(this.name, this.membersCount);
   void hello() {} //형태만 강제
}

class BoyGroup implements Idol {
  String name;
  int membersCount;
  BoyGroup(this.name, this.membersCount);
  void hello(){
    print("My name is $name we have $membersCount boys");
  }
}

class GirlGroup implements Idol {
  String name;
  int membersCount;
  GirlGroup(this.name, this.membersCount);
  void hello(){
    print("My name is $name we have $membersCount girls");
  }
}
void main() {
  BoyGroup bg = BoyGroup("BTS", 5);
  BoyGroup gg = BoyGroup("Nespa", 6);
  
  Idol idol = Idol("boy", 7); // Error
}

abstract 키워드는 interface를 인스턴스화하는 것을 막을 수 있다.

mixin

  • mixin은 자식클래스의 생성없이 물려줄 수 있는 도구이다.
  • 다중 상속을 피하기 위하여 사용
  • with키워드를 이용하여 사용한다.

※ 다중 상속을 피해야하는 이유↓ https://siyoon210.tistory.com/125

mixin이 필요한 이유(mixin 미사용시)

abstract class Insect{
  void crawl() {
    print("crawling");
  }
}

abstract class AirbornInsect extends Insect {
  void flutter() {
    print("fluttering");
  }
  void buzz() {
    print("buzzing annoyingly");
  }
}


abstract class Bird{
  void chirp() {
    print("chirping");
  }
  // Duplicated method
  void flutter(){
    print("fluttering");
  }
}

class Mosquito extends AirbornInsect{
  void doMosquitoThing(){
    crawl();
    flutter();
    buzz();
    print("Sucking blood");
  }
}

class Swallow extends Bird {
  void doSwallowThing(){
    chirp();
    flutter();
    print("Eating a mosquito");
  }
}

2개의 서로 다른 클래스에서 flutter method가 중복으로 사용됨

mixin이 필요한 이유(mix인 사용)

mixin Fluttering {
  void flutter(){
    print("fluttering");
  }
}

abstract class Insect{
  void crawl() {
    print("crawling");
  }
}

abstract class AirbornInsect extends Insect with Fluttering{
  void buzz() {
    print("buzzing annoyingly");
  }
}


abstract class Bird with Fluttering{
  void chirp() {
    print("chirping");
  }
}

class Mosquito extends AirbornInsect{
  void doMosquitoThing(){
    crawl();
    flutter();
    buzz();
    print("Sucking blood");
  }
}

class Swallow extends Bird {
  void doSwallowThing(){
    chirp();
    flutter();
    print("Eating a mosquito");
  }
}

코드의 중복을 피하면서 Fluttering class만 상속 가능

Fluttering 클래스 상속 구조

mixin 사용법

 abstract class Walk{
   final String foot = "Small Foot";
   void walk(){
     print("Walk with $foot");
   }
 }
  1. abstract class
mixin Walk{
   final String foot = "Small Foot";
   void walk(){
     print("Walk with $foot");
   }
 }
  1. mixin 키워드

mixin의 on

  1. 특정 클래스만 해당 mixin 상속 가능하게 함

  2. 해당 클래스의 타입의 변수와 메소드를 사용가능하다.

  3. mixin으로 선언된 경우에만 사용가능

class FlyingAnimal {
  final String name;
  FlyingAnimal(this.name);
  void fly() {
    print("$name is flying");
  }
}

mixin Walk on FlyingAnimal{
  final String foot = "Small foot";
  void walk() {
    print("$name is Walk with $foot");
    fly();  // FlyingAnimal method 사용가능
  }
}

class Minsu extends FlyingAnimal with Walk {
  Minsu(String name): super(name);
  void hi() {
    print("hi");
    walk();
  }
}

/* Walk은 on으로 FlyingAnimal에만 사용가능하게
한것을 Sumin 클래스에 상속하려해서 에러 발생
*/
class Sumin with Walk{
  void sumin(){
    print("sumin");
  }
}

Walk는 on을 사용하여 FlyingAnimal에만 상속 가능 한데 Sumin에 상속하려 했기 때문에 에러가 발생

작성자: YunSukHyun

태그:

카테고리:

업데이트:

댓글남기기