Foggy day

[Dart] 클래스(class)에 대하여 - 2 본문

Flutter/Dart 문법

[Dart] 클래스(class)에 대하여 - 2

jinhan38 2023. 3. 3. 20:46

 

 

이번 포스팅에서는 클래스의 상속, 추상클래스, implements(interface), mixin을 사용하는 방법에 대하여 알아보겠습니다. 

 

 

 

1. 상속

Dart는 Java나 Kotlin처럼 extends키워드를 이용해 1개의 클래스만 상속받을 수 있습니다. 이때 상속당하는 클래스가 부모클래스, 상속을 하는 클래스는 자식 클래스라고 합니다. 

 

Animal 클래스와 Lion 클래스가 있습니다.

Lion 클래스는 extends라는 키워드로 Animal을 상속받고 있습니다. 이때 Animal클래스가 부모 클래스, Lion클래스가 자식 클래스입니다. 자식 클래스는 부모 클래스에 있는 함수와 변수를 사용할 수 있습니다. 

 

class Animal {

  void eat(){}
  
}

class Lion extends Animal {
	
    Lion(){
    	eat();
    }

}

 

 

 

2. 추상클래스

추상클래스를 사용하는 이유는 자식 클래스가 추상클래스의 메소드들을 반드시 구현하도록 강제하기 때문입니다. 그렇게 되면 A라는 추상클래스를 상속받은 클래스들은 모두 동일한 형태의 함수를 구현하게 됩니다. 이는 코드의 가독성과 유지보수의 기능을 향상시켜줍니다. 

 

추상클래스는 class 키워드 앞에 abstract 키워드를 붙이면 됩니다. 추상클래스는 함수를 구현해도 되고, 구현하지 않아도 됩니다. 반면 일반 클래스는 함수를 만들 때 반드시 구현부도 있어야 합니다. 함수를 구현하고 안 하고의 구분은 중괄호가 있고 없고로 구분할 수 있습니다. 함수를 구현하지 않았을 경우 상속받은 클래스가 구현하지 않은 함수를 반드시 구현해야 합니다. 이것을 override라고 합니다. 함수들 위에 @override annotation이 붙어있다면 부모의 클래스에 있는 함수를 자식 클래스에서 구현한다는 것입니다. 
추상클래스에서 함수를 구현한 경우 자식 클래스에서는 반드시 구현하지 않아도 됩니다. 그런데 구현할 경우 super.함수명()을 통해 부모 클래스에서 구현한 함수를 호출할 수 있습니다. 

추상클래스가 일반 클래스와 다른 점은 일반 클래스는 인스턴스화가 가능하지만(생성자를 통해 생성이 가능) 추상클래스는 불가능합니다. 오직 extends(상속), with, implements 키워드를 통해서만 사용 가능합니다. 

abstract class Animal {
  void eat();

  /// 함수를 구현하지 않은 형태
  void sleep();

  // /// 함수를 구현한 형태
  void run(){
    print('Animal.run 도망간다');
  }
}



class Dog extends Animal{
  @override
  void eat() {}

  @override
  void sleep() {}

  @override
  void run() {
    /// override는 부모 클래스의 함수를 재정의 하는 것이다.
    /// 부모 클래스에서 구현하지 않은 함수는 override가 필수이고,
    /// 구현한 함수의 override는 자유이다.
    /// 부모 클래스인 Animal의 run 함수를 호출하기 위해서는 super.함수명();
    /// super.run(); 코드를 삭제하면 부모 클래스의 run 구현부는 호출되지 않는다.
    super.run();
  }

}

 

 

 

3. implements

implements는 interface 클래스를 사용할 때 필요한 키워드입니다. 다만 자바나 코틀린에서는 interface키워드를 사용할 수 있지만 dart에서는 interface 키워드가 없습니다. 그래서 interface클래스처럼 사용할 클래스를 만들어서 implements를 하면 됩니다. interface클래스는 보통 함수만 있는 경우가 많고, interface를 implements한 자식 클래스는 interface 클래스의 함수를 모두 override해야합니다.

예제의 AnimalInterface클래스(인터페이스)는 int 변수, String 변수,  함수가 각각 1개씩 있습니다. AnimalInterface 클래스를 상속받은 Bird 클래스는 두개의 변수와 한개의 함수를 모두 구현해야 합니다. 

/// 인터페이스로 사용할 클래스는 abstract 키워드를 사용할 수도
/// 사용하지 않을 수도 있습니다.
/// 인터페이스는 사용하는 클래스가 반드시 구현해야 할 것들을 정리해 놓은 것입니다.
/// impelemnts 키워드와 함께 사용할 수 있습니다.
abstract class AnimalInterface {
  late int age;

  late String name;

  AnimalInterface(this.age, this.name);

  void cry();

}

class Bird implements AnimalInterface {
  @override
  int age = 0;

  @override
  String name = "";

  @override
  void cry() {}
}

 

 

 

4. mixin

mixin은 Dart에 있는 다중상속 기능이라고 이해하면 됩니다. mixin 키워드가 있는 클래스는 with 키워드와 함께 상속받을 수 있고, 자식 클래스는 여러개를 mixin 클래스를 상속받을 수 있습니다. Interface와 다른점은 interface를 구현하면 모든 함수와 변수를 자식클래스에서 override해야 했지만, mixin클래스는 override할 필요 없이 변수나 함수를 호출할 수 있습니다. 다만 mixin클래스에서 함수의 구현부가 없다면 자식 클래스가 override 해야합니다. 

예제에서 보면 mixin 클래스인 Item 클래스의 cloth 함수를 Bird 클래스 생성자에서 호출하고 있습니다. 

/// mixin 클래스는 오직 with 키워드와 함께 사용할 수 있다.
mixin Item {
  void cloth(){
    print('Item.cloth 함수 호출');
  }
}

abstract class AnimalInterface {
  late int age;

  late String name;

  AnimalInterface(this.age, this.name);

  void cry();

}

class Bird with Item implements AnimalInterface {
  Bird() {
  	// 생성자에서 mixin 클래스인 Item 클래스의 함수를 호출 
    cloth();
  }

  @override
  int age = 0;

  @override
  String name = "";

  @override
  void cry() {}
}

 

 

이렇게 클래스의 상속, 추상클래스, implements(interface), mixin의 사용법에 대하여 알아봤습니다. 이러한 사용법들을 이해한다면 객체지향 언어에 대한 이해와 다른 언어습득에도 많은 도움이 될 것입니다.