Interface
인터페이스는 구현 방식과 무관하게 어떤 연산을 제공해야 하는지만 선언하는 계약입니다. 호출자는 구체 클래스가 아니라 이 계약에 의존함으로써 구현체가 바뀌어도 코드 구조를 크게 흔들지 않을 수 있습니다.
▶아키텍처 다이어그램
🔗 관계 다이어그램점선 애니메이션은 데이터 또는 요청의 흐름 방향을 나타냅니다
호출 코드가 구체 클래스 이름과 내부 구현에 직접 묶여 있으면 저장 방식 하나 바꾸는 일도 크게 번집니다. 테스트에서는 대체 구현을 끼우기 어렵고, 운영 코드에서는 외부 연동 방식을 바꿀 때 상위 계층까지 함께 수정해야 합니다.
대규모 시스템에서는 같은 역할을 여러 구현체가 맡는 일이 흔합니다. 메모리 저장과 DB 저장, 실제 결제 게이트웨이와 테스트 더블처럼 역할은 같고 구현만 다른 경우를 안정적으로 다루려면 클래스 이름보다 역할 계약이 먼저 보여야 했습니다. 이런 배경에서 인터페이스 중심 설계가 널리 퍼졌습니다.
인터페이스는 메서드 이름, 입력과 출력, 호출자가 기대할 수 있는 계약만 정의합니다. 여러 클래스가 이 계약을 구현하면 호출자는 실제 구현체의 타입을 몰라도 됩니다. 중요한 것은 누가 구현했는가보다 이 계약을 지키는가입니다.
인터페이스와 추상 클래스는 둘 다 공통 표면을 만들지만 초점이 다릅니다. 인터페이스는 구현 공유 없이 역할 계약을 드러내는 데 집중하고, 추상 클래스는 그 계약 위에 공통 로직까지 얹습니다. 공통 구현이 필요 없다면 인터페이스가 더 가볍고 명확합니다.
알림 전송기, 저장소 어댑터, 결제 게이트웨이, 정책 객체처럼 역할은 유지한 채 구현체를 바꿔 끼워야 하는 자리에서 인터페이스가 잘 맞습니다. 반대로 구현체가 하나뿐이고 대체 가능성도 거의 없는데 습관적으로 인터페이스를 두면 유연성보다 추상화 비용만 늘 수 있습니다.