객체 지향 인터페이스
📋 문서 버전
이 문서는 2개의 버전이 있습니다. 현재 최신 버전을 보고 있습니다.
객체 지향 인터페이스
개요
객체 지향 인터페이스Object-Oriented Interface)는 객체 지 프로그래밍(OOP, Object-Oed Programming)에서가 제공하는 기능의 외부와의 연결점을 의미합니다. 이는 클래스가 외부에 공개하는 메서드와 속성의 집합으로, 다른 객체나 모듈이 해당 클래스를 사용할 수 있도록 정의된 계약(contract)의 역할을 합니다. 인터페이스는 구현 세부 사항을 숨기고, 추상화를 통해 코드의 유연성과 재사용성을 높이는 핵심 설계 요소입니다.
인터페이스는 단순한 메서드 목록을 넘어서, 시스템 내 구성 요소 간의 상호작용 방식을 명확히 정의하며, 설계 원칙인 의존성 역전(Dependency Inversion)과 인터페이스 분리(Interface Segregation)를 실현하는 데 중요한 역할을 합니다.
인터페이스의 개념
정의와 목적
인터페이스는 특정 클래스가 어떤 기능을 제공해야 하는지를 선언(declaration)하는 추상적인 틀입니다. 실제 구현은 해당 인터페이스를 구현하는 클래스에서 이루어지며, 인터페이스 자체는 구현 코드를 포함하지 않습니다.
예를 들어, Drawable
이라는 인터페이스는 draw()
메서드를 선언할 수 있으며, Circle
, Rectangle
클래스는 이 인터페이스를 구현하여 각자의 방식으로 draw()
를 정의합니다.
public interface Drawable {
void draw();
}
public class Circle implements Drawable {
public void draw() {
System.out.println("원을 그립니다.");
}
}
이러한 구조는 클라이언트 코드가 구체 클래스가 아닌 인터페이스에 의존하게 하여, 결합도를 낮추고 확장성을 높입니다.
인터페이스와 추상 클래스의 차이
항목 | 인터페이스 | 추상 클래스 |
---|---|---|
메서드 구현 | 기본적으로 없음 (Java 8+에서 default 메서드 가능) | 일부 메서드에 구현 가능 |
상태(필드) | 상수만 가능 (static final) | 인스턴스 필드 가능 |
다중 상속 | 가능 (여러 인터페이스 구현) | 불가능 (단일 상속) |
목적 | "할 수 있는 행위" 정의 | 공통 속성과 기능의 기본 구현 제공 |
인터페이스의 설계 원칙
1. 인터페이스 분리 원칙 (ISP)
인터페이스 분리 원칙(Interface Segregation Principle)은 클라이언트가 자신이 사용하지 않는 메서드에 의존하지 않아야 한다는 원칙입니다. 즉, 하나의 방대한 인터페이스보다, 목적에 따라 여러 개의 작은 인터페이스를 분리하는 것이 바람직합니다.
예:
// 나쁨: 모든 기능이 하나의 인터페이스에 포함
public interface Machine {
void print();
void scan();
void fax();
}
// 좋음: 역할별로 인터페이스 분리
public interface Printer {
void print();
}
public interface Scanner {
void scan();
}
이렇게 하면 PrinterOnlyDevice
클래스가 불필요하게 scan()
이나 fax()
메서드를 구현할 필요가 없습니다.
2. 의존성 역전 원칙 (DIP)
의존성 역전 원칙(Dependency Inversion Principle)은 고수준 모듈이 저수준 모듈에 직접 의존하지 말고, 둘 다 추상화(인터페이스)에 의존해야 한다는 원칙입니다.
예:
public class ReportGenerator {
private Printer printer; // 인터페이스에 의존
public ReportGenerator(Printer printer) {
this.printer = printer;
}
public void generate() {
// ... 보고서 생성 로직
printer.print();
}
}
이 구조는 ReportGenerator
가 LaserPrinter
나 InkjetPrinter
와 같은 구체 클래스에 묶이지 않고, 테스트와 유지보수를 용이하게 합니다.
인터페이스의 활용 사례
1. 플러그인 아키텍처
인터페이스는 플러그인 시스템을 구현할 때 핵심입니다. 예를 들어, 에디터 프로그램이 다양한 포맷의 파일을 열 수 있도록 하기 위해 [FileOpener](/doc/%EA%B8%B0%EC%88%A0/%EC%86%8C%ED%94%84%ED%8A%B8%EC%9B%A8%EC%96%B4%20%EC%84%A4%EA%B3%84/%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4/FileOpener)
인터페이스를 정의하면, 각 포맷별로 구현 클래스를 추가할 수 있습니다.
public interface FileOpener {
Document open(String path);
}
public class PdfOpener implements FileOpener { ... }
public class DocxOpener implements FileOpener { ... }
런타임에 적절한 구현체를 주입함으로써 확장성이 보장됩니다.
2. 단위 테스트와 Mocking
인터페이스는 단위 테스트에서 Mock 객체를 사용하기 위해 필수적입니다. 예를 들어, 데이터베이스 접근을 인터페이스로 추상화하면, 테스트 시 실제 DB 대신 가짜(mock) 객체를 주입할 수 있습니다.
public interface UserRepository {
User findById(int id);
}
// 테스트 시 MockUserRepository 사용 가능
언어별 인터페이스 지원
언어 | 인터페이스 지원 여부 | 특징 |
---|---|---|
Java | O | interface 키워드로 정의, 다중 구현 가능 |
C# | O | interface 키워드, default 구현 가능 (C# 8.0+) |
Python | X (공식 키워드 없음) | abc.ABC 와 추상 메서드로 흉내 가능 |
TypeScript | O | interface 로 타입 정의 및 클래스 구현 가능 |
C++ | X | 가상 함수를 사용한 추상 클래스로 대체 |
참고 자료 및 관련 문서
- SOLID 원칙 - Wikipedia
- Java 인터페이스 공식 문서
- Design Patterns: Elements of Reusable Object-Oriented Software (GoF)
결론
객체 지향 인터페이스는 소프트웨어 설계에서 유연성, 확장성, 테스트 용이성을 보장하는 핵심 요소입니다. 잘 설계된 인터페이스는 시스템의 복잡성을 관리하고, 모듈 간의 결합도를 낮추며, 변화에 강한 아키텍처를 구축하는 데 기여합니다. 개발자는 인터페이스를 단순한 메서드 선언이 아닌, 시스템의 행동 계약으로 인식하고 설계해야 합니다.
이 문서는 AI 모델(qwen-3-235b-a22b-instruct-2507)에 의해 생성된 콘텐츠입니다.
주의사항: AI가 생성한 내용은 부정확하거나 편향된 정보를 포함할 수 있습니다. 중요한 결정을 내리기 전에 반드시 신뢰할 수 있는 출처를 통해 정보를 확인하시기 바랍니다.