Dart 인터페이스(Interface) 설명 및 예제
1. 인터페이스란?
인터페이스(Interface)는 클래스가 특정 동작을 수행하도록 강제하는 계약(contract)입니다. Dart에서는 추상 클래스(abstract class) 를 사용하여 인터페이스를 정의할 수 있으며, 다른 클래스에서 이를 구현(implement) 할 수 있습니다.
Dart에서는 다른 객체 지향 언어(Java, C# 등)와 달리 interface 키워드가 없습니다. 대신, 모든 클래스가 암묵적으로 인터페이스 역할을 하며, implements 키워드를 사용하여 특정 클래스의 인터페이스를 구현할 수 있습니다.
2. Dart에서 인터페이스의 특징
- Dart에서는 모든 클래스가 인터페이스 역할을 함.
- implements 키워드를 사용하여 인터페이스를 구현할 수 있음.
- 인터페이스를 구현할 경우, 모든 메서드와 변수를 반드시 재정의(override) 해야 함.
- 다중 구현이 가능함(여러 개의 인터페이스를 동시에 구현 가능).
3. 인터페이스의 기본 사용법
Dart에서는 abstract class 를 사용하여 인터페이스를 정의하고, implements 키워드를 사용하여 이를 구현할 수 있습니다.
예제 1: 기본적인 인터페이스 구현
// 인터페이스 역할을 하는 추상 클래스
abstract class Animal {
void makeSound(); // 추상 메서드
}
// Dog 클래스에서 Animal 인터페이스 구현
class Dog implements Animal {
@override
void makeSound() {
print("멍멍!");
}
}
// Cat 클래스에서 Animal 인터페이스 구현
class Cat implements Animal {
@override
void makeSound() {
print("야옹~");
}
}
void main() {
Dog dog = Dog();
Cat cat = Cat();
dog.makeSound(); // 출력: 멍멍!
cat.makeSound(); // 출력: 야옹~
}
설명
- Animal 클래스는 추상 클래스이며, makeSound()라는 추상 메서드를 가짐.
- Dog와 Cat 클래스는 Animal을 implements 하여 인터페이스를 구현함.
- 인터페이스를 구현한 클래스는 반드시 makeSound() 메서드를 재정의해야 함.
4. 다중 인터페이스 구현
Dart에서는 여러 개의 인터페이스를 동시에 구현할 수 있습니다.
예제 2: 다중 인터페이스 구현
abstract class Flyable {
void fly();
}
abstract class Swimmable {
void swim();
}
// 새는 날 수도 있고, 수영도 가능하므로 두 인터페이스를 구현함
class Duck implements Flyable, Swimmable {
@override
void fly() {
print("오리가 날아갑니다!");
}
@override
void swim() {
print("오리가 수영합니다!");
}
}
void main() {
Duck duck = Duck();
duck.fly(); // 출력: 오리가 날아갑니다!
duck.swim(); // 출력: 오리가 수영합니다!
}
설명
- Flyable과 Swimmable 두 개의 인터페이스를 정의.
- Duck 클래스가 Flyable, Swimmable을 모두 구현하여 다중 인터페이스를 사용.
5. 인터페이스 vs 상속의 차이점
Dart에서 extends(상속)와 implements(인터페이스 구현)는 다르게 동작합니다.
비교 항목 extends (상속) implements (인터페이스)
| 코드 재사용 | 부모 클래스의 메서드를 재사용 가능 | 모든 메서드를 새로 구현해야 함 |
| 다중 적용 | 단일 상속만 가능 (하나의 부모 클래스만 가질 수 있음) | 여러 개의 인터페이스를 구현 가능 |
| 필드 상속 | 부모 클래스의 필드도 상속됨 | 인터페이스에서는 필드도 반드시 재정의 필요 |
예제 3: 상속과 인터페이스 비교
// 상속을 사용하는 경우
class Parent {
void sayHello() {
print("Hello from Parent");
}
}
class Child extends Parent {}
void main() {
Child child = Child();
child.sayHello(); // 상속받은 메서드를 그대로 사용 가능
}
// 인터페이스를 사용하는 경우
abstract class Speaker {
void sayHello();
}
class Person implements Speaker {
@override
void sayHello() {
print("Hello from Person");
}
}
void main() {
Person person = Person();
person.sayHello(); // 반드시 재정의 필요
}
설명
- extends는 부모 클래스의 메서드를 그대로 사용할 수 있음.
- implements는 모든 메서드를 반드시 재정의해야 함.
6. 인터페이스와 믹스인(Mixin) 비교
Dart에서는 Mixin을 사용하여 코드 재사용성을 높일 수도 있습니다. 인터페이스와 믹스인은 다르게 동작하므로, 적절한 상황에서 사용해야 합니다.
예제 4: 인터페이스 vs 믹스인
// 인터페이스 사용
abstract class Walker {
void walk();
}
class Human implements Walker {
@override
void walk() {
print("사람이 걷는다.");
}
}
// 믹스인 사용
mixin Runner {
void run() {
print("빠르게 달립니다!");
}
}
class Athlete with Runner {}
void main() {
Human human = Human();
human.walk(); // 출력: 사람이 걷는다.
Athlete athlete = Athlete();
athlete.run(); // 출력: 빠르게 달립니다!
}
차이점
- implements는 인터페이스로 사용되며, 모든 메서드를 직접 구현해야 함.
- mixin은 기존 클래스에 기능을 추가할 때 사용하며, 이미 구현된 메서드를 제공.
7. 실제 활용 예제: 서비스 인터페이스
Dart에서 인터페이스는 의존성 주입(DI, Dependency Injection) 및 서비스 분리에 자주 사용됩니다.
예제 5: 데이터 저장소 인터페이스
// 데이터 저장소 인터페이스 정의
abstract class StorageService {
void save(String key, String value);
String? load(String key);
}
// 파일 저장소 구현
class FileStorage implements StorageService {
Map<String, String> storage = {};
@override
void save(String key, String value) {
storage[key] = value;
print("파일에 저장: $key -> $value");
}
@override
String? load(String key) {
return storage[key];
}
}
// 데이터베이스 저장소 구현
class DatabaseStorage implements StorageService {
Map<String, String> db = {};
@override
void save(String key, String value) {
db[key] = value;
print("데이터베이스에 저장: $key -> $value");
}
@override
String? load(String key) {
return db[key];
}
}
void main() {
StorageService storage = FileStorage();
storage.save("username", "dart_user");
print(storage.load("username")); // 출력: dart_user
}
설명
- StorageService 인터페이스를 정의하고, FileStorage와 DatabaseStorage에서 각각 구현.
- 프로그램 실행 시 StorageService의 구현체를 선택하여 사용할 수 있음.
8. 결론
- Dart에서는 abstract class 를 사용하여 인터페이스를 정의.
- implements 를 사용하면 모든 메서드를 반드시 구현해야 함.
- 다중 인터페이스 구현이 가능하여 유연한 설계를 지원.
- 인터페이스는 다형성, 의존성 주입, 서비스 분리 등에서 활용됨.
Dart에서 인터페이스를 활용하면 유지보수성이 높고 확장성이 좋은 코드를 작성할 수 있습니다! 🚀
'Programming > Dart' 카테고리의 다른 글
| Dart Abstract (0) | 2025.03.28 |
|---|---|
| Dart Mixins (0) | 2025.03.28 |
| Dart Override (0) | 2025.03.27 |
| Dart Inheritance (1) | 2025.03.25 |
| Dart 파일 구조 (0) | 2025.03.25 |