Dart에서 클래스는 어떻게 사용할까?
기본적인 클래스 및 생성자 구조와 다양한 속성들에 대해 기록하였다.


Basic Class

class Player {
    // Class에서 property를 정의할 때는 Type을 지정해준다.
    String name = "JP"; // 외부에서 이름 변경 가능
    final String name = "JP"; // 이러면 외부에서 이름 못바꿈
    int xp = 1500;

    void sayHello() {
        var name = "JPJP";
        // Dart의 클래스에서는 this를 사용하지 않는다. $this.name이 아닌 그냥 $name을 사용
        print("Hi my name is $name"); 
        // 만약 함수 내부에 새로운 name이 정의되었고 이를 사용하려면 아래와 같이 사용한다.
        print("Hi my name is ${this.name}")
    }
}

void main() {
    var player = Player();
    player.name; // JP
    player.xp;  // 1500
}

Constructors

class Player {
    late final String name;
    int xp;

    // Dart에서 Constructor는 아래와 같이 정의
    Player(String name, int xp) {
        this.name = name;
        this.xp = xp;
    }

    // 위 Player Constructor와 같음
    Player(this.name, this.xp);
}

void main() {
    var player = Player("JP", 31);
}

Named Constructor Parameters

class Player {
    late final String n ame;
    int xp, age;
    String team;

    // 위 Player Constructor와 같음
    // 이러면 각 인자가 null로 들어올 수 있다고 에러가 난다.
    // default 값을 정해주거나, required 수식어를 붙여준다.
    Player({this.name = "Default", required this.xp, required this.team, required this.age});
}

void main() {
    // 아래 방법은 positional 이므로 함수처럼 optional로 설정 가능하다.
    var player = Player("JP", 31, "red", 12);

    // optional
    var player = Player(name:"JP", age:12, team:"red", xp:31);
}

Named Constructor

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

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

    // 아래와 같은 코드로 용도에 맞는 생성자를 구성할 수 있다.
    // ':'을 사용함으로써 Player 객체를 원하는 설정에 맞게 초기화하는 것으로 이해하자.
    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 main() {
    var bluePlayer = Player.createBluePlayer(name:"JP", age:21);
    var redPlayer = Player.createRedPlayer("EL", 23);
}

Cascade Notation

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

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

void main() {
    // 생성자 인스턴스를 만들고 맨 마지막에 세미콜론을 생략한 채 .. + 속성에 접근하여 수정할 수 있다.
    // 이것이 바로 Cascade Notation이다
    var user = Player(name:"JP", xp:0, team:"blue", age:21)
    ..name = 'EL'
    ..xp = 9999
    ..team = 'red';
}

Enums

// Enum을 지정해줌으로써 파라미터를 잘못 넘기는 것을 방지해준다.
// 마치 TypeScript에서 인자로 받을 수 있는 파라미터를 지정해 주는 것과 같다.
enum Team {red, blue}

class Player {
    late final String name;
    int xp, age;
    // enum으로 정의된 Team을 타입으로 설정했기 때문에 team은 red or blue만 받을 수 있다.
    Team team;

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

void main() {    
    var user = Player(name:"JP", xp:0, team:"blue", age:21)
    ..name = 'EL'
    ..xp = 9999
    ..team = Team.blue; // 변경도 enum 범위 안에서 변경해야 한다.
}

Abstract Classes

// Human 추상 클래스는 walk라는 메서드를 가지고 있다.
// 기능이 정의되지는 않았지만 일반 클래스에서 Human 추상메서드를 구현하면 walk 메서드를 꼭 구현해야한다.
abstract class Human {
    void walk();
}

class Player extends Human {
    // extends는 상속이기 때문에 walk 함수의 내용이 채워져 있다면 재정의를 하지 않아도 된다.
    // 그러나 이번 케이스에서는 Human -> walk 메서드가 정의만 되어있어서 재정의 필요
    void walk() {
        print('im walking');
    }
}

class Coach implements Human {
    // implements는 인터페이스 구현이기 때문에 무조건 walk 메서드 재정의가 필요하다.
    void walk() {
        print('the coach is walking');
    }
}

Inheritance

class Human {
    final String name;
    Human(this.name);
    void sayHellao() {
        print('Hi my name is $name');
    }
}

enum Team {red, blue}

class Player extends Human {
    final Team team;

    // 생성자 뒤에 : super 키워드를 통해 부모 클래스와 상호작용 할 수 있다.
    Player({
        required this.team,
        required String name
    }) : super(name);

    // override 키워드 안써줘도됌.
    @override
    void sayHello() {
        super.sayHello();
        print("and I play for ${team}");
    }
}

void main() {
    var player = Player(team:Team.red, name:'JP');
    player.sayHello();
}

Mixins

enum Team {red, blue}

// mixin은 아래와 같이 선언한다.
// 생성자가 존재하지 않아야 한다.
mixin Strong {
  final double strengthLevel = 1500.99;
}

mixin QuickRunner {
  void runQuick() {
    print("runnnnnn!");
  }
}

mixin Tall {
  final double height = 1.99;
}

// mixin 클래스를 사용하려면 with 키워드를 사용한다.
class Player with Strong, QuickRunner, Tall {
  final Team team;

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

class Horse with Strong, QuickRunner {
  //...
}

void main() {
  var player = Player(name:"JP", team:Team.red);
  //player는 Player 클래스 인스턴스이면서 QuickRunner mixin 클래스를 사용하므로 runQuick 함수 사용이 가능하다.
  player.runQuick();
}

'Mobile' 카테고리의 다른 글

[Flutter] Flutter 설치방법  (0) 2023.10.12
[Flutter] Flutter의 동작 방식  (0) 2023.10.10
[Dart] Dart의 Function 사용법  (0) 2023.10.10
[Dart] Dart의 Data Types  (0) 2023.10.09
[Dart] Dart의 변수 정의  (3) 2023.10.09

+ Recent posts