Dart

[Dart] Dart Docs - Classes(1)

  • -
728x90

Dart는 Class와 Mixin 기반 상속을 지원하는 객체지향언어다. 모든 객체는 클래스의 인스턴스이고, Null을 제외한 클래스는 모두 Object에서 비롯한다.

Mixin 기반 상속이란 말은, 모든 클래스가 하나의 부모 클래스를 가지고 있지만 (최상위 클래스인 Object 제외) 클래스의 바디는 다양한 클래스 계층에서 재사용 될 수 있음을 의미한다. 

 

Dart는 extension-methods(확장 메소드)라는 것도 제공하는데, 이는 서브 클래스를 생성하거나, 클래스를 바꾸지 않고 클래스에 기능을 추가하는 방법이다. 

 

아래의 예시로 클래스에 대해 알아보자.

import 'dart:math';

class Point {
  double x;
  double y;
  double z = 0;
  
  Point(this.x, this.y, [this.z = 0]);
  
  Map<String, double> getPoint()=>{'x':x, 'y':y, 'z':z};
  
  double distanceTo(Point b){
    final dx = x - b.x;
    final dy = y - b.y;
    final dz = z - b.z;
    
    return sqrt(dx * dx + dy * dy + dz * dz);
  }
}

void main() {
  final p = Point(1,1);
  final q = Point(4,5);
  final curr = p.getPoint();
  final dist = p.distanceTo(q);
  
  print(dist);
}

 

클래스 멤버 사용하기

객체는 함수와 데이터로 구성된 멤버가 있다. 메소드를 호출 할 때, 객체에서 함수를 호출한다. 메소드는 호출할 때 객체 위에서 실행하므로 메소드는 객체의 함수와 데이터에 접근 할 수 있다.

"."을 사용하면 인스턴스 변수나 메소드를 참조할 수 있다.

 

생성자 사용하기

생성자를 사용하여 객체를 만들 수 있다.

생성자 이름은 ClassName 이나 ClassName.identifier 이다.

 

몇몇 클래스는 상수 생성자를 제공한다.

var p = const ImmutablePoint(2, 2);

 

상수 문맥에서 생성자나 리터럴 전에 const 키워드를 생략할 수 있다.

 

// 다수의 const 키워드가 있습니다.
const pointAndLine = const {
    'point': const [const ImmutablePoint(0, 0)],
    'line': const [const ImmutablePoint(1, 10), const ImmutablePoint(-2, 11)],
};

 

모두 생략 가능하나 첫번째 const 키워드는 사용해야 한다.

// 상수 문맥을 시작하는 한개의 const만 존재
const pointAndLine = {
    'point': [ImmutablePoint(0, 0)],
    'line': [ImmutablePoint(1, 10), ImmutablePoint(-2, 11)],
};

 

 

인스턴스 변수

모든 초기화되지 않은 인스턴스 변수는 null 값을 가진다.

 

모든 인스턴스 변수는 암시적인 getter 메소드를 생성한다. 또한 final이 아닌 인스턴스 변수와 초기화없는 late final 인스턴스 변수는 암시적인 setter 메소드를 생성한다.

void main() {
    final point = Point();
    point.x = 4; // x의 setter 메소드를 사용
	print(point.x); // x의 getter 메소드를 사용
	print(point.y == null); // 기본값은 null
}

 

 

추상 클래스

인스턴스가 될 수 없는 추상 클래스를 정의하기 위해서 "abstract" 수식어를 사용한다.

 

추상클래스를 사용하는 이유는 주로 자주 구현되는 인터페이스를 정의하는데 있어서 유용하다.

추상 클래스를 인스턴스화할 수 있도록 보이려면, 팩토리 생성자를 정의한다.

// 이 클래스는 추상으로 선언되며 인스턴스화가 불가합니다.
abstract class AbstractContainer {
    // 생성자, 필드, 메소드를 선언...

    void updateChildren(); // 추상 메소드
}

 

 

암시적 인터페이스

모든 클래스는 암묵적으로 클래스와 구현된 인터페이스의 모든 인스턴스 멤버를 포함한 인터페이스를 정의한다.

B의 구현을 상속하지 않고 B클래스의 API를 지원하는 클래스 A를 생성하려면, 클래스 A는 B 인터페이스를 구현해야한다.

 

A클래스는 implements 절에 선언된 한개 이상의 인터페이스를 구현하며 해당 인터페이스에 필요한 API를 제공한다.

// Person, greet()를 포함한 암시적 인터페이스
class Person {
    // 인터페이스에 있지만 이 라이브러리에서만 볼 수 있음
    final String _name;

    // 생성자이기 때문에 인터페이스에 없음
    Person(this._name);

    // 인터페이스
    String greet(String who) => 'Hello, $who. I am $_name.';
}

// Person 인터페이스 구현체
class Impostor implements Person {
    String get _name => '';

    String greet(String who) => 'Hi $who. Do you know who I am?';
}

String greetBob(Person person) => person.greet('Bob');

void main() {
    print(greetBob(Person('Kathy')));
    print(greetBob(Impostor()));
}

 

정적 변수, 정적 함수

import 'dart:math';

class Point {
  double x;
  double y;
  double z = 0;
  static String? name;
  
  // Point(this.x, this.y, this.name [this.z = 0]); -> name은 인스턴스에 존재하지 않음
  Point(this.x, this.y, [this.z = 0]);
  
  Map<String, double> getPoint()=>{'x':x, 'y':y, 'z':z};
  
  double distanceTo(Point b){
    final dx = x - b.x;
    final dy = y - b.y;
    final dz = z - b.z;
    
    return sqrt(dx * dx + dy * dy + dz * dz);
  }
  
  void printInfo() {
    print('x: ${x} y: ${y} z: ${z} name: $name');
  }
}

void main() {
  final p = Point(1,1);
  final q = Point(4,5);
  
  p.printInfo();
  q.printInfo();
  
  Point.name = "점";
//   p.name = "p점"; line 35 • The static setter 'name' can't be accessed through an instance.
//  q.name = "q점"; 
  
  p.printInfo();
  q.printInfo();
}

 

static으로 선언된 변수와 함수는 인스턴스에서 동작하지 않고 사용되기 전까지 초기화 되지 않는다.

클래스 전반적인 변수와 메소드를 구현할 때 사용한다.

728x90
300x250
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.