[Dart 언어강좌] 010. 객체지향 프로그래밍 (OOP) 소개, 추상 클래스와 인터페이스

프로그램을 구조적이고 효율적으로 작성하는 데 중요한 개념 중 하나는 객체지향 프로그래밍(Object-Oriented Programming, OOP)입니다. Dart 언어는 이러한 OOP 개념을 바탕으로 설계된 언어로, 코드를 재사용하고 유지보수하기 쉽게 만들어 줍니다. OOP의 중요한 구성 요소인 추상 클래스와 인터페이스를 살펴보겠습니다.

1. 객체지향 프로그래밍(OOP) 개념

객체지향 프로그래밍은 프로그램을 ‘객체’라는 독립적인 단위로 구성하여 문제를 해결하는 방식입니다. 객체는 상태(속성)와 동작(메서드)을 포함하여 프로그램의 로직을 모듈화할 수 있게 합니다. 주요 OOP 개념은 다음과 같습니다:

  • 캡슐화(Encapsulation): 객체의 내부 상태를 보호하고, 외부에서 접근할 수 없도록 하는 방법입니다. 이를 통해 코드의 재사용성과 유지보수성을 높입니다.
  • 상속(Inheritance): 기존 클래스를 기반으로 새로운 클래스를 생성하여, 코드의 재사용성과 기능 확장을 용이하게 합니다.
  • 다형성(Polymorphism): 동일한 이름의 메서드가 다양한 동작을 수행하도록 하는 기능입니다. 이는 프로그램의 유연성을 증가시킵니다.

2. 추상 클래스(Abstract Class)

추상 클래스는 완전한 구현이 아닌 메서드의 정의를 포함하는 클래스입니다. 추상 클래스는 다른 클래스에 상속받아 사용되며, 직접 인스턴스화할 수 없습니다. 이는 프로그래머에게 강력한 설계 계약을 제공하는 역할을 합니다.

단순한 추상 클래스 예제

아래는 Dart에서 추상 클래스를 정의하고 사용하는 예제입니다.

abstract class Animal {
    void sound(); // 추상 메서드
}

class Dog extends Animal {
    @override
    void sound() {
        print("멍멍!");
    }
}

class Cat extends Animal {
    @override
    void sound() {
        print("야옹!");
    }
}

void main() {
    Animal dog = Dog();
    Animal cat = Cat();
    
    dog.sound(); // 멍멍!
    cat.sound(); // 야옹!
}

위 예제에서 <code>Animal</code> 클래스는 추상 클래스이며, <code>sound()</code>이라는 추상 메서드를 정의하고 있습니다. <code>Dog</code>와 <code>Cat</code> 클래스는 <code>Animal</code> 클래스를 상속받아 이 메서드를 구현합니다.

추상 클래스의 활용

추상 클래스는 특정 클래스의 공통 기능을 정의하여 코드의 중복을 줄이고, 유지보수를 용이하게 합니다. 이러한 특성 덕분에 확장성과 유연성을 높일 수 있습니다. 예를 들어, 다양한 동물 클래스를 정의할 때, 각 클래스의 공통된 특징을 추상 클래스에서 정의할 수 있습니다.

3. 인터페이스(Interfaces)

인터페이스는 클래스가 구현해야 하는 메서드의 집합을 정의합니다. Dart에서는 인터페이스를 클래스로 정의하고, 이를 다른 클래스에서 구현함으로써 다양한 객체가 동일한 메서드를 지원하도록 강제할 수 있습니다. Dart는 만약 클래스가 다른 클래스의 기능을 상속받지 않는 경우, 그 클래스를 인터페이스처럼 사용할 수 있습니다.

인터페이스 예제

아래는 간단한 인터페이스를 사용하는 예제입니다.

class Drawable {
    void draw();
}

class Circle implements Drawable {
    @override
    void draw() {
        print("Circle을 그립니다.");
    }
}

class Square implements Drawable {
    @override
    void draw() {
        print("Square을 그립니다.");
    }
}

void main() {
    Drawable circle = Circle();
    Drawable square = Square();
    
    circle.draw(); // Circle을 그립니다.
    square.draw(); // Square을 그립니다.
}

위 예제에서 <code>Drawable</code> 인터페이스는 <code>draw()</code> 메서드를 정의합니다. <code>Circle</code>와 <code>Square</code> 클래스는 이 인터페이스를 구현하여 자신의 방식으로 그리기 기능을 제공합니다. 이를 통해 다양한 형태의 도형을 처리할 수 있는 유연성을 확보할 수 있습니다.

4. 추상 클래스와 인터페이스의 차이

추상 클래스와 인터페이스는 유사한 목적을 가지고 있지만, 다음과 같은 차이점이 있습니다:

  • 추상 클래스는 상태를 가질 수 있지만, 인터페이스는 상태를 가질 수 없습니다.
  • 추상 클래스는 메서드의 기본 구현을 가질 수 있지만, 인터페이스는 메서드에 대한 구현을 제공할 수 없습니다.
  • 하나의 클래스는 여러 인터페이스를 구현할 수 있지만, 하나의 클래스는 단지 하나의 추상 클래스만 상속할 수 있습니다.

5. 결론

객체지향 프로그래밍은 현대 소프트웨어 개발에서 필수적인 부분이며, Dart 언어는 이를 명확하게 실현하도록 설계되었습니다. 추상 클래스인터페이스는 이러한 OOP 개념을 더욱 효과적으로 활용할 수 있는 도구입니다. 이를 통해 코드의 유연성과 재사용성을 높이고, 프로젝트의 복잡성을 관리할 수 있습니다. Dart를 사용하는 개발자라면 이러한 개념을 잘 이해하고 활용함으로써 더 나은 소프트웨어 개발을 할 수 있을 것입니다.