앞에서 상속은 다른 클래스의 멤버를 그대로 사용하는 방법이라고 했습니다. 그런데 추상 클래스나 인터페이스를 이용하면 다른 클래스의 멤버를 그대로 사용하지 않고 새로 구현하게 할 수 있습니다.
추상 클래스 알아보기
추상 클래스는 추상 함수만 제공하여 상속받는 클래스에서 반드시 재정의해서 사용하도록 강제하는 방법입니다. 추상 함수는 실행문이 작성된 본문이 없는 함수를 의미합니다. 다음 코드에서는 일반 클래스로 선언한 User에 some() 함수를 선언했지만 중괄호로 본문 영역을 누락해서 오류가 발생합니다.
// 추상 함수 선언
class User {
void some(); // 오류
}
이처럼 본문을 생략한 추상 함수를 선언할 때는 이 함수가 속한 클래스에 abstract 예약어를 붙여 추상 클래스로 선언해야 합니다. 즉, 추상 함수는 abstract를 붙인 추상 클래스에서만 선언할 수 있습니다.
// 추상 클래스 선언
abstract class User {
void some(); // 성공
}
추상 클래스는 객체를 생성할 수 없습니다. 추상 클래스는 앞에서 설명한 대로 자식 클래스에게 함수를 재정의해서 사용하라고 강제하는 수단입니다. 즉, 다음처럼 추상 클래스를 상속받은 자식 클래스에서 추상 함수를 재정의해 줘야 합니다.
// 추상 함수 재정의
abstract class User {
void some();
}
class Customer extends User {
@override
void some() {}
}
인터페이스 알아보기
인터페이스란 부모의 특징을 도구로 사용해 새로운 특징을 만들어 사용하는 객체지향 프로그래밍 방법입니다. 그런데 다트에서는 대부분의 객체지향 언어에서 지원하는 interface 예약어를 지원하지 않습니다.
다음 코드는 자바 언어로 인터페이스를 구현한 예입니다. 자바 언어에서는 interface라는 예약어로 인터페이스를 선언하며, implements라는 예약어로 인터페이스를 구현하는 클래스를 선언합니다. 그리고 인터페이스를 구현하는 클래스는 인터페이스에 선언된 추상 함수를 재정의해야 합니다.
// 자바로 인터페이스 구현
interface MyInterface { // 인터페이스 선언
void fun1();
}
public class MyClass implements MyInterface { // 인터페이스 구현
public void fun1() { // 함수 재정의
}
}
그런데 다트에서는 implements만 지원하고 interface는 지원하지 않습니다. 즉, 인터페이스를 명시적으로 선언하지 않아도 다른 클래스를 도구 삼아 구현하는 방법을 제공합니다. 이를 암시적 인터페이스 라고 합니다. 암시적 인터페이스란 클래스 자체가 인터페이스 라는 의미입니다. 즉, 클래스를 implements로 선언하면 다른 클래스를 인터페이스로서 활용 할 수 있다는 의미입니다.
다음 코드에서는 User는 변수 2개와 생성자 1개, 함수 1개를 선언한 일반 클래스입니다.
// 일반 클래스
class User {
int no;
String name;
User(this.no, this.name);
String greet(String who) => 'Hello, $who. I am $name. no is $no';
}
이렇게 선언한 클래스를 다음처럼 extends로 상속받아 자식 클래스를 선언할 수 있습니다.
// User의 자식 클래스 선언
class MySubClass extends User {
MySubClass(super.name, super.no);
}
그런데 implements 예약어를 추가하면 User 클래스를 본떠 새로운 클래스를 구현할 수 있습니다. 다음 코드에서 User 클래스는 암시적 인터페이스가 되고, MyClass는 User를 새로 구현한 클래스가 됩니다.
// 인터페이스 구현 클래스 선언
class MyClass implements User { // 오류
}
그런데 이 선언문은 오류가 발생합니다. 왜냐하면 클래스에 implements를 추가해 어떤 클래스를 구현하는 클래스는 대상 클래스에 선언된 모든 멤버를 재정의해야 하기 때문입니다. 즉, implements로 인터페이스를 구현하는 클래스를 선언할 수 있는데, 이때 인터페이스에 선언된 멤버를 구현 클래스에서 모두 재정의해 줘야 합니다.
// 인터페이스의 모든 멤버 재정의
class MyClass implements User {
int no = 10;
String name = 'kim';
@override
String greet(String who) {
return 'hello';
}
}
하나의 클래스에 여러 인터페이스를 지정해서 선언할 수도 있습니다.
// 한 클래스에 여러 인터페이스 지정
class MyClass implements User, MyInterface {
}
그리고 구현 클래스의 객체는 다음처럼 인터페이스 타입으로 선언할 수 있습니다.
// 인터페이스 타입 객체 선언
main() {
User user = MyClass();
print('${user.greet('lee')}');
}
'Flutter' 카테고리의 다른 글
화면을 구성하는 위젯 (0) | 2024.11.15 |
---|---|
멤버를 공유하는 믹스인 (1) | 2024.11.15 |
상속 알아보기 (0) | 2024.11.14 |
상수 생성자 (0) | 2024.11.14 |
팩토리 생성자 (0) | 2024.11.14 |