Dart 클래스

Gavri·2022년 9월 19일

Flutter

목록 보기
10/14

개요


이번 Velog 포스트에서는 Dart에서 클래스를 사용하는 방법에 대해 설명합니다.


클래스

다트는 클래스와 믹스인 기반 상속이 있는 객체 지향 언어입니다. 모든 객체는 클래스의 인스턴스이며 Null을 제외한 모든 클래스는 Object 클래스를 상속받았으며, Mixin 기반 상속은 여러 클래스를 상속 받을 수 있습니다. 또한 확장 메서드를 활요해 클래스를 변경하거나 하위 클래스를 만들지 않고 클래스에 기능을 추가하는 방법이 있습니다.

클래스 선언 생성자 인스턴스화 멤버 접근

class Animal {
  // 클래스 내에 변수 지정
  String type;
  String name;

  //  생성자
  Animal(this.name, this.type); // this를 통해 클래스 내 변수에 접근가능
}

void main(){
	Animal cat = Animal("루미","고양이"); // 인스턴스화
    // 생성자를 사용해 인스턴스화
    print(cat.name) // "루미" 
    // 객체에는 함수와 데이터로 구성된 멤버가 있으며 접근하기 위해선 객체에 .을 통해 접근가능
    
    print(cat.runtimeType) // Animal 객체 타입을 가져오는 방법
    
}

클래스 변수

모든 클래스 변수는 암시적 getter 메서드를 생성합니다.
setter의 경우 final,const가 붙지 않은 경우 암시적으로 생성됩니다.

class Animal {
  // 클래스 내에 변수 지정
  String type;
  String name;

  final bool isAnimal;
  late int? age; // ?를 통해 초기에 null이 들어가며 추후에 값이 추가됨을 표시

  //  생성자
  Animal({required this.name, required this.type, this.isAnimal = true});

  //  선언적 get 사용방법 : 타입 get 함수이름 => 값
  int? get getAge => age; 
  //  선언적 set 사용방법 : set 함수이름(파라미터) => 변경할 변수 = 값;
  set setAge(int value) => age = value;
}

void main(List<String> args) {
  Animal cat = Animal(name: "에옹이", type: "고양이", isAnimal: true);

  // setter 
  cat.setAge = 10; 
  cat.age = 10;

  // getter
  print(cat.getAge);
  print(cat.age);
}

생성자

  • 기본 생성자 : 생성자를 선언하지 않아도 생성자가 제공되며,이 경우 인수가 없는 슈퍼 클래스 생성자를 호출합니다
  • 생성자는 상속되지 않아 하위 클래스는 상위 클래스 생성자를 상속 하지 않습니다.
  • 명명된 생성자 : 클래스에 대해 여러 생성자를 구현하거나 추가 명확성을 제공합니다.
class Animal {
  // 클래스 내에 변수 지정
  String type;
  String name;

  //    생성자 객체 형태로 인자를 받기
  Animal({required this.name, required this.type});
  // 	명명된 생성자 
  Animal.origin(this.name, this.type);
  
  Animal.origin2(getName,getType):
  		name = getName,
        type = getType;
}

슈퍼클래스 생성자 호출

기본적으로 하위 클래스 생성자는 상위 클래스의 기본 생성자를 호출합니다.

하위 생성자 실행순서
1. 초기화 목록
2. 슈퍼클래스의 인수가 없는 생성자
3. 기본클래스의 인수가 없는 생성자

Person을 상속한 Employee에서 수퍼 클래스 생성자 호출 하는 예제

class Person {
  String? firstName;

  Person.fromJson(Map data) {
    print('in Person');
  }
}

class Employee extends Person {
  // Person does not have a default constructor;
  // you must call super.fromJson().
  Employee.fromJson(super.data) : super.fromJson() {
    print('in Employee');
  }
}

void main() {
  var employee = Employee.fromJson({});
  print(employee);
  // Prints:
  // in Person
  // in Employee
  // Instance of 'Employee'
}

생성자 리디렉션,상수 생성자

class Point {
  double x, y;

  // 메인 생성자.
  Point(this.x, this.y);

  // 메인 생성자를 리디렉션 하는 생성자.
  Point.alongXAxis(double x) : this(x, 0);
}
/// 상수 생성자
class ImmutablePoint {
	// 컴파일 타임 상수
  static const ImmutablePoint origin = ImmutablePoint(0, 0);
	// 인스턴스 생성시 상수로 지정
  final double x, y;

  const ImmutablePoint(this.x, this.y);
}

factory 생성자

새 인스턴스를 반환하지 않는 생성자를 만들때 사용하는 factory 생성자 입니다. 캐시에서 인스턴스를 반환하거나 하위 유형의 인스턴스를 반환할 수 있습니다. 팩토리 생성장의 또 다른 사용 사례는 초기화 목록에서 처리할 수 없는 논리를 사용하여 최종 변수를 초기화 하는 것입니다.

팩토리 생성자는 this에 접근할 수 없습니다.

class Logger {
  final String name;
  bool mute = false;

  // _cache is library-private, thanks to
  // the _ in front of its name.
  static final Map<String, Logger> _cache = <String, Logger>{};

  factory Logger(String name) {
    return _cache.putIfAbsent(name, () => Logger._internal(name));
  }

  factory Logger.fromJson(Map<String, Object> json) {
    return Logger(json['name'].toString());
  }

  Logger._internal(this.name);

  void log(String msg) {
    if (!mute) print(msg);
  }
}

abstract

추상 클래스추상 메서드를 가질 수 있는 클래스를 의미한다.
추상 메서드란? 선언은 되어 있지만 바디가 정의되지 않은 함수를 의미한다.

추상 클래스의 특징

  1. 추상 클래스는 미완성 클래스여서 객체를 생성할 수 없다.
  2. 참조형 변수의 타입으로는 사용이 가능하다.
  3. 추상 클래스를 implements 한 클래스는 추상 메서드를 오버라이딩 해야한다.
abstract class Person {
  //추상 클래스
  eat(); // 추상 메서드 바디가 없다

  Person();
  sleep() {
    // 일반 메서드
    print("zzz...");
  }
}

class Man implements Person {
  @override // @override는 생략가능
  eat() {
    print("eat");
  }

  sleep() {
    print("zzz...");
  }
}

void main() {
  Man man = Man();

  man.eat(); // eat
  man.sleep(); // zzz...
}

클래스 상속

extends 키워드를 활용해 하위 클래스에서 상위 클래스를 상속하며,
super 키워드를 통해 상위 클래스를 참조하는데 사용합니다.

noSuchMethod 메소드를 활용해 존재하지 않는 메서드나 인스턴스 변수를 사용하려고 할 대마다 감지하거나 반응할 수 있습니다.

class Person {
  eat() {
    print("입으로 먹기");
  }

  sleep() {
    print("zzz...");
  }

  String run(String where) {
    var runString = "$where으로 달리기";
    print(runString);
    return runString;
  }
}

class Man extends Person {
  @override // @override는 생략가능
  eat() {
    super.eat();
    print("eat");
  }

  @override
  String run(String where) {
    return super.run(where);
  }

  @override
  // 선언하지 않은 메서드 또는 변수를 사용하는 경우
  noSuchMethod(Invocation invocation) {
    print("선언하지 않은 변수를 사용 : ${invocation.memberName}");
    return super.noSuchMethod(invocation);
  }
}

void main() {
  Man man = Man();

  man.eat(); // 입으로 먹기 , eat
  man.sleep(); // zzz...
  man.run("한강"); // 한강으로 달리기
}

Enum 열거형

단순 열거형 : enum enumName { 열거할 데이터들...} 앞에서부터 0,1,2 값을 가진다
향상된 열거형 : 상수 인스턴스의 고정된 수로 제한되는 필드,함수 및 const 생성자가 있는 클래스를 선언 가능

// 단순 열거형
enum Color { red, green, blue }

// 향상된 열거형
enum Vehicle {
  car(tires: 4, passengers: 5, carbonPerKilometer: 400), // 각각의 Enum 인스턴스 하나이상의 인스턴스가 존재해야됌
  bus(tires: 6, passengers: 50, carbonPerKilometer: 800),
  bicycle(tires: 2, passengers: 1, carbonPerKilometer: 0);

  const Vehicle({
    // 생성자 const 타입의 생성자
    required this.tires,
    required this.passengers,
    required this.carbonPerKilometer,
  });

  final int tires; // 인스턴스 변수
  final int passengers;
  final int carbonPerKilometer;

  int get carbonFootprint => (carbonPerKilometer / passengers).round(); // 메소드
  
}

void main(List<String> args) {
  print(Vehicle.car.carbonPerKilometer);
}

Mixin 믹스인

믹스인은 여러 클래스 계층에서 클래스 코드를 재사용 하는 방법입니다.
mixin 키워드를 활용해 클래스를 선언하면 인스턴스 변수는 늘리되 생성자는 생성하지 않는 클래스를 만듭니다.

class A {...}
class B {...}
class C {...}
class AWithBAndC extends A with B,C {
	...
}

mixin Musical {
	bool canSing = true;
}
class Person extends Musical{
	...
}

void main(){
	print(Person().canSing); // true
}

클래스 변수 및 메서드

static 키워드를 활용해 정적 변수 및 메서드를 만들 수 있습니다.
정적 변수와 메서드는 인스턴스화를 하지 않아도 접근이 가능합니다.

	class Queue {
  static const initialCapacity = 16;
  
  static func(){...}
  // ···
}

void main() {
  assert(Queue.initialCapacity == 16);
  Queue.func();
}
profile
모든건 기록으로

0개의 댓글