[Dart] 4. Class 클래스 #1

yunulog·2023년 1월 3일
0

Dart

목록 보기
4/5

4. CLASSES

0. Your First Dart Class

Class 를 생성할 땐 타입을 꼭 명시해주어야 한다.

class Player {
  String name = 'Jack';
  int xp = 1500;
}

위처럼 반드시 데이터 타입을 명시해준다.

class Player {
  String name = 'Jack';
  int xp = 1500;
}

void main() {
  var player = new Player();
  print(player.name);
}

var player = new Player(); 라는 코드는 Player라는 클래스를 이용해서 인스턴스를 하나 만들어준다.
new 는 붙여도 되고 안붙여도 된다.

player.name 이나 player.age 같은 코드로 내용에 접근할 수도 있다.

데이터를 재할당하는 것도 가능하다.

class Player {
  String name = 'Jack';
  int xp = 1500;
}

void main() {
  var player = new Player();
  print(player.name);
	// Jack
  player.name = 'Me';
  print(player.name);
	// Me
}

데이터 재할당을 불가능하게 하고 싶다면 데이터 타입 앞에 final만 붙여주면 된다.

class Player {
  final String name = 'Jack';
  int xp = 1500;
}

void main() {
  var player = new Player();
  print(player.name);
	// Jack
  player.name = 'Me'; // -> Error
}

class 안에서 데이터를 참조해서 함수를 만들 땐
$데이터명 으로 데이터를 끌어오면 된다.
Javascript와 달리 this. 는 쓰지 않아도 된다. (써도 되지만 권장X)

class Player {
  String name = 'Jack';
  int xp = 1500;

  void sayHello () {
    print("안녕 내 이름은 $name");
  }
}

void main() {
  var player = new Player();
  player.sayHello();
	// 안녕 내 이름은 Jack
}

1. Constructors

위에서 만든 클래스는 이름과 xp가 정해져있으므로 모든 player 의 이름과 xp가 같다.

그래서 argument로 이름과 xp를 전달해 새로운 player를 생성하는 클래스를 만드려고 한다.

이때 사용하는게 Consructor(생성자)인데 클래스 안에 만들어주면 되고 클래스의 이름과 같은 이름으로 만들어주어야 한다.

  1. 클래스에서 디폴트값으로 설정된 값들을 지워주고
    데이터타입 앞에는 late를 붙여 생성자를 통해 추후에 데이터가 들어올 것임을 명시해준다.
  2. 클래스와 같은 이름의 생성자를 클래스 안에 만들어준다.
    this. 를 써서 클래스에 있는 데이터들을 끌어온다.
  3. main 함수 안에서 클래스 생성자를 이용해 다양한 플레이어들을 만들어준다!
class Player {
  late final String name;
  late int xp;

  Player (String name, int xp) {
    this.name = name;
    this.xp = xp;
  }

  void sayHello () {
    print("안녕 내 이름은 $name");
  }
}

void main() {
  var player = new Player("Suzy", 1300);
  player.sayHello();
	// 안녕 내 이름은 Suzy
  var player2 = new Player("Mii", 1500);
  player2.sayHello();
	// 안녕 내 이름은 Mii
}

위 코드를 보면 데이터타입이 이미 클래스를 만들때 명시되어있음에도 생성자를 만들때 다시 명시되는 것을 볼 수 있다.
이런 중복을 줄여 더 간단하게 만들 수 있다.

late를 없애고 생성자에 바로 this.를 넣어줌으로써 생성자에 입력되는 값이 클래스의 name과 xp로 간다는 것을 명시해주는 방법이다.

class Player {
  final String name;
  int xp;

  Player (this.name, this.xp);

  void sayHello () {
    print("안녕 내 이름은 $name");
  }
}

void main() {
  var player = new Player("Suzy", 1300);
  player.sayHello();
	// 안녕 내 이름은 Suzy
  var player2 = new Player("Mii", 1500);
  player2.sayHello();
	// 안녕 내 이름은 Mii
}

2. Named Constructor Parameters

지금까지는 Positional Argument 만 사용했다.
즉, 데이터를 참조할 때 반드시 순서를 지켜서 참조해야한다.

언뜻보면 편리한 방식같지만 클래스가 커지면 상황이 달라진다.

player클래스에 teamage가 있다고 해보자.

class Player {
  final String name;
  int xp;
  String team;
  int age;

  Player (this.name, this.xp, this.team, this.age);

  void sayHello () {
    print("안녕 내 이름은 $name");
  }
}

void main() {
  var player = new Player("Suzy", 1300, 'red', 12);
  player.sayHello();
  var player2 = new Player("Mii", 1500, 'blue', 15);
  player2.sayHello();
}

데이터가 네개가 되자 순서가 헷갈리기 시작한다.
특히 외부에서 함수를 끌어와서 사용할땐 더더욱 그렇다.
이런 경우를 대비해 Named Argument를 사용한다.

방법은 간단하다.

생성자 안을 중괄호로 묶어주고
main 함수에서 생성자를 사용할 때 데이터이름을 명시해주면 된다.

그런데 그냥 이렇게 사용하면 null safety 때문에 생성자 안 데이터에 빨간줄이 그어질 것이다.

이를 해결하는 두가지 방법이 있는데

  1. 디폴트값을 설정해주거나
  2. 데이터 앞에 required를 붙여주거나
class Player {
  final String name;
  int xp;
  String team;
  int age;

  Player ({required this.name, required this.xp, required this.team, required this.age});

  void sayHello () {
    print("안녕 내 이름은 $name");
  }
}

void main() {
  var player = new Player(name:"Suzy", xp: 1300, team: 'red', age: 12);
  var player2 = new Player(name:"Lynn", xp: 1300, team: 'blue', age: 15);
}

물론 생성자를 사용할 때 안의 데이터들은 순서가 바뀌어도 상관없다.

  • 데이터 타입이 같을 땐 한 줄에 여러 데이터를 명시해주어도 된다.

int xp; int age;

int xp, age;

3. Named Constructor

현재까지 만든 클래스는 name, xp, team, age 라는 데이터를 반드시 받아서 사용하는 클래스이다.

두명의 플레이어를 만드는데 name과 age만 입력하고 한명은 xp가 0인 red팀, 한명은 xp가 0인 blue팀을 만드려고 한다.

우선 createBluePlayer라는 생성자와 createRedPlayer라는 생성자를 만든다.

콜론(:)을 사용할건데 클래스의 데이터들을 원하는 방식으로 초기화할 때 사용한다.
여기서 : 뒤에 age와 name은 클래스의 age와 name을 끌어와서 사용한다.
그리고 team과 xp는 원하는 데이터 값으로 명시해준다.

Player.createBluePlayer({required String name, required int age}) :
  this.age = age,
  this.name = name,
  this.team = 'blue',
  this.xp = 0;

Player.createRedPlayer(required String name, required int age) :
  this.age = age,
  this.name = name,
  this.team = 'Red',
  this.xp = 0;

createBluePlayernamed argument,
createRedPlayerpositional argument이다.

class Player {
  final String name;
  int xp, age;
  String team;

  Player ({required this.name, required this.xp, required this.team, required this.age,});

  Player.createBluePlayer({required String name, required int age}) :
  this.age = age,
  this.name = name,
  this.team = 'blue',
  this.xp = 0;

  Player.createRedPlayer(String name, int age) :
  this.age = age,
  this.name = name,
  this.team = 'Red',
  this.xp = 0;

  void sayHello () {
    print("안녕 내 이름은 $name");
  }
}

void main() {
  var player = Player.createBluePlayer(name:"Suzy", age: 12);
  var player2 = Player.createRedPlayer("Lynn", 15);
}

4. Recap

위에서 배운 내용들을 적용해보는 시간이다.

아래 클래스는 다음과 같다.
fromJson 이라는 생성자를 만들었다.
Json 형식의 내용을 기반으로 하는 생성자이다.
key값이 문자열이고 value값으로 다양한 데이터타입을 받는 playerJson이라는 데이터를 받는다.

main함수 내에서는 apiData라는 이름의 json 데이터를 받는다.
apiData.forEach 함수로 각 요소에 대해 fromJson 생성자를 실행한다.
그리고 각 player 마다 sayHello 함수를 실행한다.

class Player {
  final String name;
  int xp;
  String team;

  Player.fromJson(Map<String, dynamic> playerJson) :
    name = playerJson['name'],
    xp = playerJson['xp'],
    team = playerJson['team'];

  void sayHello () {
    print("안녕 내 이름은 $name");
  }
}

void main() {
  var apiData = [
    {
      'name': 'A',
      'team': 'blue',
      'xp': 0,
    },
    {
      'name': 'B',
      'team': 'blue',
      'xp': 0,
    },
    {
      'name': 'C',
      'team': 'blue',
      'xp': 0,
    },
  ];

  apiData.forEach((playerJson) {
    var player = Player.fromJson(playerJson);
    player.sayHello();
		//안녕 내 이름은 A
		//안녕 내 이름은 B
		//안녕 내 이름은 C
   });
}

다음글 [Dart] 4. Class 클래스 #2

<참고>
[노마드코더] Dart 강좌

0개의 댓글