본문 바로가기
flutter 공부 기록소

Flutter 공부 기록 4

by riddleuscode 2023. 6. 16.

이번에는 객체지향 프로그래밍과 관련된 부분을 살펴보겠습니다.

일단 클래스를 만들어볼게요.

 

class Ghost{
  String name;
  int lv;
  int hp;
  int atk;
  
}

만들긴 했지만, 안쪽에 빨간줄이 네개나 뜹니다. 오류문은

Non - nullable instance field 'name' must be initialized.  Try adding an initializer expression, or a generative constructor that initializes it, or mark it 'late'.

(대강 번역해보면 "Non - nullable 인스턴스는 초기화가 필요하다, 초기화 표현이나 생성자를 사용하거나 late 표현을 사용하라" ) 

Non - nullable이 문제라면 지난번에 배웠던 ?를 사용한다면 nullable로 바뀌겠죠?

class Ghost{
  String? name;
  int? lv;
  int? hp;
  int? atk;

}

빨간줄은 사라지긴 하지만, 생성자를 만들어 해결해보겠습니다.

generate -> constructor로 만들어보려고 했는데 모든 필드를 동시에 선택할 순 없네요.. 

그냥 직접 손으로 치겠습니다.

 

class Ghost{
  String name;
  int lv;
  int hp;
  int atk;

  Ghost(String name, int lv, int hp, int atk):
        this.name=name,
        this.lv=lv,
        this.hp=hp,
        this.atk=atk;
}

자바와 다른점으로 콜론을 사용하고, {}로 묶지 않고, ","를 통해 여러 변수를 한꺼번에 처리합니다.

 

Ghost(this.name, this.lv,this.hp, this.atk);

 

this를 사용하면 이렇게 간단하게 작성이 가능합니다. 

 

이번엔 getter와 setter를 넣어보겠습니다. 그런데, private 속성의 필드만 만들수 있다는 메시지가 뜨네요?

그래서 자바처럼 private을 변수의 타입 앞에다가 붙여주면.. 안되고, 찾아보니 변수명 앞에 _를 붙이면

private 속성을 갖게 되는 것 같습니다. (다만, dart에서는 같은 파일에서만 접근할 수 있는 변수의 의미라는 점을 주의해주세요)

그래서 바꿔본 후 다시 getter과 setter를 넣어보면,

class Ghost{
  String _name;
  int _lv;
  int _hp;
  int _atk;


  int get lv => _lv;

  set lv(int value) {
    _lv = value;
  }


  int get hp => _hp;

  set hp(int value) {
    _hp = value;
  }


  String get name => _name;

  set name(String value) {
    _name = value;
  }


  int get atk => _atk;

  set atk(int value) {
    _atk = value;
  }

  Ghost(String name, int lv, int hp, int atk):
        this._name=name,
        this._lv=lv,
        this._hp=hp,
        this._atk=atk;

  
}

이번엔 generate-> Getter and Setter를 사용했습니다. 한번에는 안되는 것 같아서 4번에 걸쳐서 추가했어요.

getter는 람다식을 사용했는데, 람다식이 아닐때는

int get lv{
  return this._lv;
}

이런식으로 함수명 뒤에 ()가 붙지 않습니다. 매개변수를 사용하지 않는다는 의미죠.

공통적으로 타입 뒤에 get이나 set이 붙고 그 다음에 함수명의 순서로 작성한다는 점 기억해둬야겠습니다.

 

이번에는 클래스를 생성해서 getter 및 setter를 사용해보겠습니다.

 

void main() {
  Ghost g= Ghost("퍼스", 5, 100, 10);
  print(g.name);
  g.name= "유우";
  print(g.name);

  runApp(const MyApp());
}

결과로 "퍼스"랑 "유우"가 순서대로 나왔습니다.

객체를 생성하는건 new가 없다는 점만 빼면 자바랑 형태는 똑같군요!

 

g.name 으로 꺼내오면 getter,

g.name ="유우"로 변경하면 setter

간단하고 편리하죠?

처음 자바배울때 public 변수를 getter랑 setter 없이 가져오고 변경할때 사용하던 방식이랑 똑같이 생겼습니다.

이건 dart의 큰 장점이라고 생각합니다.

 

이어서 네임드 생성자를 만들어보겠습니다.

Ghost.fromMap(Map<String,dynamic>map):
      this._name= map["name"],
      this._lv= map["lv"],
      this._hp= map["hp"],
      this._atk= map["atk"];

매개변수로 Map을 입력받는 생성자입니다. 

변수는 Map의 키를 통해 값을 받습니다. 사용해보면

void main() {
  Ghost g= Ghost.fromMap({
    "name":"퍼스","lv": 5,"hp" : 100, "atk": 10
  });
  print(g.lv);
  g.lv= 100;
  print(g.lv);

  runApp(const MyApp());
}

json 입력하듯 콜론과 쉼표를 이용해서 Map을 넣어줍니다.

 

 

Ghost를 상속받는 클래스를 만들어보겠습니다.

class Perth extends Ghost{
  String _specialty;
  //Perth(super.name, super.lv, super.hp, super.atk,this._specialty);
  Perth(String _name, int _lv, int _hp,int _atk,this._specialty):super(_name,_lv,_hp,_atk);
}

 

Ghost에게서 extends로 상속을 받아 Perth라는 클래스를 만들었습니다.

주석친것과 그 아래에 있는 것 , 두 방법 다 상속을 받아 생성자를 만드는 방법입니다.

다만, 전자는 필드를 상속받아서 만드는 느낌, 후자는 생성자 자체를 상속받아서 만드는 느낌이네요.

새로 추가한 필드인 specialty는 부모는 가지고 있지 않으니 상속 받지 않았습니다.

 

오버라이드를 사용하기 전에, 아직 일반 매서드를 만들지 않았네요..

Ghost에 매서드를 하나 만들고 사용해보겠습니다.

void attack(Ghost){
  Ghost.hp -= this.atk;
  print("$name은(는)  ${Ghost.name} 에게 $atk만큼의 피해를 주었다. 남은 체력(${Ghost.hp})");
}
void main() {
  Ghost g= Ghost.fromMap({
    "name":"유우","lv": 10,"hp" : 1000, "atk": 200
  });
  Perth perth= Perth("퍼스",15,2000,100,"고집");
  perth.attack(g);

  runApp(const MyApp());
}

결과: "퍼스은(는)  유우 에게 100만큼의 피해를 주었다. 남은 체력(900)"

 

이번엔 override를 사용하고 name을 고정시켜서 사용해보겠습니다.

class Perth extends Ghost{
  String _specialty;
  final String _name="퍼스";

  Perth(super.name,super.lv, super.hp, super.atk,this._specialty);
  //Perth(String _name, int _lv, int _hp,int _atk,this._specialty):super(_name,_lv,_hp,_atk);

  //@override
  void attack(Ghost) {
    Ghost.hp -= this.atk;
    print("퍼스는 ${Ghost.name} 에게 $atk만큼의 피해를 주었다. 남은 체력(${Ghost.hp})");

  }
}
//@override
void attack(Ghost) {
  Ghost.hp -= this.atk;
  print("퍼스는  ${Ghost.name} 에게 $atk만큼의 피해를 주었다. 남은 체력(${Ghost.hp})");

}

결과: " 퍼스는  유우 에게 100만큼의 피해를 주었다. 남은 체력(900)"

 

 

@override는 생략이 가능해서 주석처리를 해놓았고, override는 위에서 보다시피 부모가 만들어놓은 

매서드를 자신에게 맞게 다시 만드는 것 입니다. 

따라서 "은(는)"이 사라지고 "퍼스는" 으로 보이게 되는 것이죠.

 

이름이 고정되어 있으니, name값을 사용하지 않고 직접 "퍼스는"을 집어넣어 본 것이긴 한데,

뭔가 아쉬운 예제다 싶네요..

 

이번 글은 여기까지 입니다. 나머지부분은 다음 글에서 이어서 하겠습니다!

감사합니다~

 

'flutter 공부 기록소' 카테고리의 다른 글

Flutter 공부 기록 6  (0) 2023.06.18
Fluuter 공부 기록 5  (1) 2023.06.17
Flutter 공부 기록 3  (0) 2023.06.15
Flutter 공부 기록2  (0) 2023.06.14
Flutter 공부 기록1  (0) 2023.06.13