자바 인터페이스란 무엇인가?🤔 왜 SOLID 원칙을 지켜야 하죠?😎 인터페이스의 역할을 알아보자☄️ 인터페이스의 선언은 어떻게 할까?인터페이스의 구성 요소를 보고가자 !😀 인터페이스 구현단일 인터페이스 구현 클래스란?다중 인터페이스 구현 클래스익명 구현 객체(Anonymous Implement Object)🥸 인터페이스의 사용인터페이스의 구성요소를 어떻게 사용할까?😗 인터페이스 타입 변환과 다형성다형성이란?타입변환과 다형성👨👩👦 인터페이스의 상속🤖 인터페이스 디폴트 메서드와 확장디폴트메서드가 만들어진 이유🧑🏻⚖️ 결론📚 REF
자바 인터페이스란 무엇인가?
- 인터페이스는 객체지향 개발 5대원칙 SOLID를 만족시켜줄 수 있다.
🤔 왜 SOLID 원칙을 지켜야 하죠?
- 서비스 애플리케이션의 라이프사이클을 “설계, 개발, 유지보수" 세 단계로 나눈다면?
- 유지보수가 소프트웨어 라이프사이클에서 가장 큰 부분을 차지합니다.
- 유지보수에서 인터페이스는 SOLID를 구현하고 객체지향 개발을 하는데 큰 도움을 주게 됩니다.
- 설계, 개발, 유지보수 관점에서 객체 지향을 설명하면, 다음과 같은 장점이 있습니다.
- 객체지향을 사용하여 대상을 추상화하고, 추상화된 대상의 행동을 묘사하면서 설계를 쉽게 할 수 있게 합니다.
- 설계가 끝나고 개발이 진행될 때 개발자는 설계된 추상화 객체 단위로 쉽게 대상을 이해할 수 있게 됩니다.
- 개발이 완료되고 유지보수를 하면, 기존 코드와 로직을 그대로 두고, 새로운 기능을 유연하게 추가할 수 있습니다.
😎 인터페이스의 역할을 알아보자
- 인터페이스는 객체를 어떻게 구성해야 하는지 정리하는 설계도 역할을 합니다.
- 인터페이스는 객체의 교환성(또는 다형성)을 높여줍니다.
- 인터페이스 변수에 인터페이스가 구현된 서로 다른 구현 객체를 할당해서 사용이 가능합니다.
- 구현 객체를 직접 몰라도 인터페이스 메서드만 알아도 객체 호출이 가능하게 합니다.
- 객체가 인터페이스를 사용하면, 인터페이스 메서드를 반드시 구현해야 하는 제약을 합니다.

- 즉 인터페이스를 이용하여 개발 코드를 직접 수정하지 않고도 사용하고 있는 객체만 변경할 수 있도록 하기 위함입니다.
☄️ 인터페이스의 선언은 어떻게 할까?
- 인터페이스의 선언은 아래와 같습니다.
public interface 인터페이스이름 { ... } public interface 취업의길 { void 공부해라(); }
- 인터페이스의 이름은 Upper CamelCase로 작성되어야 합니다.
- interface도 Class, Enum, Annotation처럼 ~.java 파일로 작성되고 컴파일러를 통해서 바이트코드 형태의 ~.class 파일로 컴파일 됩니다.
- interface 접근 지정자로 public을 사용하면, 다른 패키지에서도 사용이 가능합니다. public을 사용하지 않으면 interface가 위치한 해당 패키지 내에서만 사용이 가능합니다.
- interface의 접근 지정자는 public만 가능합니다. 이유는 interface는 class 설계도 이기 때문에 애초에 존재 목적이 공개이기 때문입니다.
- interface는 객체로 생성할 수 없기 때문에, 생성자를 가질 수 없습니다.
- class는 상수 필드, 정적 필드, 인스턴스 필드, 생성자, 인스턴스 메서드, 정적 메서드를 구성멤버로 가지는데, interface는 상수 필드, 추상 메서드, 디폴트 메서드, 정적 메서드를 구성 멤버로 가집니다.
- Java 7 까지는 실행 블록이 없는 추상메서드로만 선언이 가능했지만 8 부터 디폴트 메서드와 정적 메서드 선언도 가능해졌습니다.
인터페이스의 구성 요소를 보고가자 !
- 상수필드(Constant Field)
- 인터페이스는 객체가 될 수 없기 때문에, 런타임에 필드 데이터를 저장할 수 없습니다. 그래서 인스턴스 필드/ 정적 필드는 선언이 불가능합니다.
- 상수 필드는 Compile Time에 선언되고 Run Time에 변경되지 않으므로 인터페이스에 선언이 가능합니다.
- [public static final] 키워드를 명시하지 않아도 자동으로 컴파일 시점에 선언되어 상수로 만들어줍니다.
- 네이밍은 모두 대문자로 구성되고 구분자는 언더바로 표현합니다. (Java Convention !)
public interface User { public static final 필드타입 상수명 = 값; String FIRST_NAME = "KIM" // 또는 public static final String FIRST_NAME = "KIM" // 은 같다. }
- 디폴트 메서드(Default Method)
- Java 8에서 추가된 인터페이스의 멤버입니다.
- 클래스의 인스턴스 메서드와 동일합니다. 즉 인스턴스 메서드입니다. 다만 인터페이스에서 선언할 때 리턴타입 앞에 default 키워드가 붙게 됩니다.
- [public]은 명시적으로 사용하지 않아도 컴파일시 자동으로 선언됩니다.
- 디폴트 메서드는 나중에 인터페이스를 구현한 구현 클래스에 인스턴스 메서드로 추가됩니다.
- 재정의를 통해서 구현 클래스에서 재정의된 인스턴스 메서드로 사용할 수 있습니다.
public interface User { // 디폴트 메서드 [public] default 리턴타입 메서드이름(매개변수, ...) { ... } // 예시 public default void setStatus(Status status) { if(statis == Status.ACTIVE) { System.out.println("사용자가 활성화 됨"); return; } System.out.println("사용자 비활성화됨"); } }
- 추상 메서드(Abstract Method)
- 인터페이스 변수로 호출된 메서드는 최종적으로 구현 객체에서 실행됩니다. 그래서 실체는 인터페이스에 없고, 구현 클래스에 있습니다.
- 추상 메서드는 리턴타입 / 메서드이름 / 매개변수가 기술되는 클래스 설계 메서드입니다.
- [public abstract]은 명시적으로 선언하지 않아도, 컴파일 시점에 자동으로 선언됩니다.
public interface User { // 추상메서드 [public abstract] 리턴타입 메서드이름(매개변수, ...) { ... }; //예시 String endMoney(Money money); // 와 public abstract String sendMoney(Money money); //는 같다. }
- 정적 메서드(Static Method)
- 자바 8에서 추가된 인터페이스의 멤버입니다.
- 선언 형식은 클래스 정적 메서드와 완전 동일합니다.
- [public]은 명시적으로 사용하지 않아도, 컴파일 시점에 자동으로 선언됩니다.
- 인터페이스의 정적 메서드도 클래스의 정적 메서드와 똑같은 방식으로 사용이 가능합니다.
public interface User { // 정적메서드 [public] static 리턴타입 메서드이름(매개변수, ...) { ... } // 예시 public static void printFirstName() { System.out.println("나의 이름은" + fistName + "입니다."); } }
😀 인터페이스 구현
- 개발 코드에서 인터페이스의 메서드를 호출하면, 인터페이스는 구현 객체의 메서드를 찾아서 호출합니다.
- 객체는 인터페이스에 있는 추상 메서드를 구현한 실체 메서드를 가지고 있어야 합니다.
- 인터페이스를 구현한 객체를 구현 객체라고 하며 구현 객체를 생성하는 클래스를 구현 클래스라고 합니다.
- 인터페이스 구현 방식은 총 세가지로 나뉩니다.
- 단일 인터페이스 구현 클래스(Single Interface Implement Class)
- 다중 인터페이스 구현 클래스(Multiple Interface Implement Class)
- 익명 구현 객체(Anonymous Implement Object)
단일 인터페이스 구현 클래스란?
public class 구현클래스이름 implements 인터페이스이름 { // 인터페이스의 추상 메서드를 구현한 실체 메서드를 선언하는 부분 } // 인터페이스 public interface User { public static final String FIRST_NAME = "Ryan"; public abstract String sendMoney(Money money); public default void setStatus(Status status) { if(status == Status.ACTIVE) { System.out.println("사용자가 활성화 되었습니다"); return; } System.out.println("사용자가 비활성화 되었습니다"); } public static void printFirstName() { System.out.println("나의 이름은 " + firstName + "입니다."); } } // 구현체 public class Recipient implements User { // 추상메서드는 다음처럼 실체 메서드를 정의해야함 ! public String sendMoney(Money money) { thirdpartyApi.send(money.getType(), money.getAmount()); return Status.SUCCESS.name(); } // 디폴트 메서드는 재정의 해도 되고 안해도 된다 }
- 만약 인터페이스를 구현한다고 하고, 추상 메서드를 구현 클래스에서 실체 메서드를 모두 작성하지 않으면 해당 구현 클래스는 추상 클래스로 선언되어야 합니다.
public abstract class Recipient implements User { }
- 인터페이스 변수에 구현 객체 대입 예시
// 유저 인터페이스를 구현한 구현 클래스 Recipient public class Recipent implements User { ... } // 유저 인터페이스를 구현한 구현 클래스 Sender public class Sender implements User { ... } User user = new Recipient(); User user = new Sender();
다중 인터페이스 구현 클래스
public class 구현클래스이름 implements 인터페이스이름1, 인터페이스이름2 { // 인터페이스의 추상 메서드를 구현한 실체 메서드를 선언하는 부분 }
- 인터페이스를 구현한 구현 클래스는 다중 인터페이스를 구현이 가능합니다.
- 다중 인터페이스를 구현한 구현 클래스는 반드시 모든 인터페이스의 추상 메서드를 실체 메서드로 구현해야 합니다.
- 하나라도 추상 메서드가 구현되지 않으면, 구현 클래스는 추상 클래스로 선언되어야 합니다.
익명 구현 객체(Anonymous Implement Object)
- 구현 클래스를 만들어서 사용하는 것이 일반적이고, 재사용이 가능하기에 편리합니다. 하지만 일회성으로 사용하는 구현 클래스는 클래스로 만들어서 쓰는 것은 비효율 적입니다.
- 비효율을 개선하기 위해서 만들어진 것이 익명 구현 객체입니다. 익명 구현 객체는 임시 작업 스레드를 만들기 위해 많이 활용됩니다.
- 특징 중에 하나는 new 키워드 뒤에 원래는 인터페이스 구현 클래스 이름이 와야하는데, 익명 구현 객체의 경우에는 참조할 구현 클래스가 없기 때문에 User 인터페이스 이름을 그대로 사용합니다.
- 다만, 익명 구현 객체의 구현 부에는 인터페이스의 추상메서드가 아닌 실체 메서드를 선언해야 합니다.
User user = new User() { public String sendMoney(Money money) { thirdpartyApi.send(money.getType(), money.getAmount()); return Status.SUCCESS.name(); } @Override public default void setStatus(Status status) { if(status == Status.ACTIVE) { System.out.println("수취인이 활성화 되었습니다"); return; } System.out.println("수취인이 비활성화 되었습니다"); } };
- 그렇다고 익명 구현 객체를 사용한다고 해서, 클래스가 생성되지 않는 것은 아니다 !
- 익명 구현 객체가 사용된 자바 파일을 컴파일 하게 되면 자동으로 익명 구현 객체의 클래스 파일이 생성됩니다.
- 생성된 익명 구현 클래스 파일의 이름은 아래와 같습니다.
- [익명 구현객체가 사용된 자바파일]$[번호].class([번호]는 1부터 시작되어, 증가합니다.)
- ex) TestExample$1.class
🥸 인터페이스의 사용
- 인터페이스 변수는 참조 타입이기 때문에 구현 객체가 대입될 경우 구현 객체의 번지가 저장됩니다.
User sender = new Sender(); // 유저 인터페이스 참조변수 sender에 Sender 객체의 번지 저장 User recipient = new Recipient(); // 유저 인터페이스 참조변수 recipient에 Recipient() 객체의 번지 저장
- 인터페이스 변수는 5개의 부분에서 구현 객체의 참조 용도로 사용될 수 있습니다.
- 클래스의 필드
- 생성자의 파라미터
- 생성자의 로컬변수
- 메서드의 파라미터
- 메서드의 로컬변수
public class TestClass { // 1.클래스의 필드 User user = new Recipient(); // 2.생성자의 파라미터 TestClass(User user) { this.user = user; // 3.생성자의 로컬변수 User recipient = new Recipient(); } // 4.메서드의 파라미터 void methodA(User user) { ... } void methodB() { // 5.메서드의 로컬변수 User user = new Recipient(); } }
인터페이스의 구성요소를 어떻게 사용할까?
// 이 예시로 동일하게 진행하겠습니다. public interface User { public static final String FIRST_NAME = "Ryan"; public abstract String sendMoney(Money money); public default void setStatus(Status status) { if(status == Status.ACTIVE) { System.out.println("사용자가 활성화 되었습니다."); return; } System.out.println("사용자가 비활성화 되었습니다."); } public static void printFirstName() { System.out.println("나의 이름은 " + firstName + "입니다."); } }
- 상수 필드의 사용(Constant Field)
User.FIRST_NAME //위 방식으로 상수는 클래스의 상수와 같은 방식으로 사용할 수 있습니다.
- 추상 메서드사용
- 유저 인터페이스의 추상 메서드 sendMoney를 호출하면 인터페이스 변수에 대입되었던 구현 객체의 주소를 판단해서 해당하는 실체 메서드를 호출하게 됩니다.
public class Example { psvm() { User user = null; user = new Recipient(); user.sendMoney(new Money(1000L)); // Recipient가 1000원을 보냈다. user = new Sender(); user.sendMoney(new Money(5000L)); // Sender가 5000원을 보냈다. } }
- 디폴트 메서드 사용
- 구현 클래스에 실체 메서드를 작성하지 않아도 구현 객체에서 호출이 가능합니다.
- 물론 구현 클래스에서 디폴트 메서드가 변경이 필요한 경우 재정의가 가능합니다. 추상메서드가 아니고 인스턴스 메서드이기 때문에 생성한 구현 객체가 있어야 사용할 수 있습니다.
- 구현 클래스에서 재정의된 디폴트 메서드가 사용되어 호출되게 됩니다.
// 일반 예 public class Example { psvm() { User user = null; user = new Recipient(); user.setStatus(Status.ACTIVE); // 사용자가 활성화 되었습니다. user = new Sender(); user.setStatus(Status.INACTIVE); // 사용자가 비 활성화 되었습니다. } } // 재정의한 예 public class Recipient implements User { @Override public default void setStatus(Status status) { if(status == Status.ACTIVE) { System.out.println("수취인이 활성화 되었습니다."); return; } System.out.println("수취인이 비활성화 되었습니다."); } } public class Sender implements User { @Override public default void setStatus(Status status) { if(status == Status.ACTIVE) { System.out.println("송신자가 활성화 되었습니다."); return; } System.out.println("송신자가 비활성화 되었습니다."); } } public class Example { public static void main(String[] args) { User user = null; user = new Recipient(); user.setStatus(Status.ACTIVE); //수취인이 활성화 되었습니다. user = new Sender(); user.setStatus(Status.INACTIVE); // 송신자가 비활성화 되었습니다. } }
- 정적메서드 사용
- 인터페이스의 정적 메서드도 클래스의 정적 메서드와 같은 방식으로 사용합니다.
- 정적 메서드이기 때문에 재정의는 불가능합니다.
public class Example { public static void main(String[] args) { User.printFirstName(); // 나의 이름은 Ryan입니다. } }
😗 인터페이스 타입 변환과 다형성
- 인터페이스는 다형성을 이용해서 타입 변환을 합니다. 타입 변환에 대한 이야기 하기에 앞서서 다형성부터 알아보겠습니다.
다형성이란?
- 하나의 타입 변수에 대입되는 객체에 따라서 실행 결과가 다양한 형태로 나오는 성질을 이야기 합니다. 즉 하나의 타입 변수를 동일한 메서드로 동작시키지만 실제 동작은 다를 수 있습니다.
- 인터페이스를 사용해서 다형성을 사용하며, 사용할 구현 객체만 바꿔주면 나머지 소스코드는 변경할 필요가 없습니다.
Interface i = new ImplementObjectA(); // i를 수정해도 i = new ImplementObjectB(); // 변경이 없습니다. i.method1(); i.method2(); // 2. 상속에서도 부모 클래스 타입의 변수에 어떤 자식 객체를 대입하냐에 따라서 객체의 메서드 실행 결과는 달라질 수 있습니다. 결국 상속에서도 인터페이스와 마찬가지로 다형성을 구현하고 있습니다. ParentClass p = new ChildClassA(); // 자식 객체로 대입이 가능하다. (다형성) p = new ChildClassB(); // 다만, ParentClass안에 구현된 메서드만 호출이 가능 p.methodAInParent(); p.methodBInParent(); // 3. 인터페이스가 매개변수로 쓰이는 경우 public class UserService { // User 인터페이스를 매개변수로 사용. public void printUserType(User user) { user.printType(); } } // User 인터페이스를 구현한 구현 객체 Recipient, Sender를 매개변수로 사용 userService.printUserType(new Recipient()); // 수취인입니다. userService.printUserType(new Sender()); // 송신자입니다.
타입변환과 다형성
- 자동 타입 변환(Promotion)
- Runtime에 구현 객체가 인터페이스 타입의 참조 변수로 자동 변환하는 것을 “자동 타입 변환"이라고 합니다.
- 자동타입 변환은 인터페이스를 구현한 구현 클래스의 자식 클래스로 만들고, 자식 객체를 인터페이스의 변수에 담아도 다형성이 적용됩니다.
- 왜 인터페이스를 구현한 클래스의 자식 클래스도 다형성이 적용되고 자동 타입 변환이 가능할까?
- 부모 클래스인 구현 클래스는 자식 클래스에게 상속을 하고 나면, 인터페이스와 마찬가지로 부모 클래스에 대한 맴버 자식 클래스에게 전달하게 됩니다.
- 결국 부모 클래스는 이미 먼저 인터페이스를 통해서 추상 메서드를 실체 메서드로 구현하였기 때문에 결국 구현된 실체 메서드가 자식 클래스에게 전달되는 것이 확실해 집니다.
- 그렇기 때문에 인터페이스를 구현한 클래스의 자식 클래스도 다형성이 적영되고 자동 타입 변환이 가능합니다.
// 인터페이스 A // 인터페이스 A를 구현한 클래스 B // 인터페이스 A를 구현한 클래스 C // 클래스 B를 상속한 자식 클래스 D // 클래스 C를 상속한 자식 클래스 E // B, C, D, E에는 printClassName를 자기 클래스 이름을 출력하는 로직이 재정의 되어있다고 가정합니다. A a1 = new B(); // OK a1.printClassName(); // B 클래스입니다. A a2 = new C(); // OK a2.printClassName(); // C 클래스입니다. A a3 = new D(); // OK a3.printClassName(); // 기본은 상속된 printClassName가 호출됩니다. "B 클래스입니다." // 만약 클래스 D의 printClassName를 재정의하면 "D 클래스입니다."가 됩니다. A a4 = new E(); // OK a4.printClassName(); // 기본은 상속된 printClassName가 호출됩니다. "C 클래스입니다." // 만약 클래스 E의 printClassName를 재정의하면 "E 클래스입니다."가 됩니다.
- 매개 변수의 다형성
- 매개변수를 인터페이스 변수로 두고, 구현 객체를 대입해주면 다형성을 적용해서 사용할 수 있습니다.
// 인터페이스 public interface User { void printType(); } // 구현 클래스 "Recipient" public class Recipient implements User { @Override public void printType() { System.out.println("수취인입니다."); } } // 구현 클래스 "Sender" public class Sender implements User { @Override public void printType() { System.out.println("송신자입니다."); } } public class Mail { public void printUserType(User user) { user.printType(); } } public class Main { public static void main(String[] args) { Mail mail = new Mail(); mail.printUserType(new Recipient()); // User user = new Recipient(); "수취인입니다." mail.printUserType(new Sender()); // User user = new Sender(); "송신자입니다." } }
- 강제 타입 변환(Casting)
- 인터페이스의 변수를 구현 객체와 사용하면, 인터페이스에서 정의된 추상 메서드 이외에는 호출할 수 없습니다.
- 즉 구현 클래스에 추가로 메서드를 구현하고 나중에 구현 객체를 사용할 때 인터페이스 변수가 사용된다면 추가로 구현된 메서드는 호출이 되지 않습니다.
- 따라서 다음과 같은 방법으로 해결합니다.
- 직접 구현 클래스 변수에 구현 객체를 대입한다.
Recipient recipient = new Recipient();
User user = new Recipient(); Recipient recipient = (Recipient) user;
// 인터페이스 public interface User { void printType(); } // 구현 클래스 "Recipient" public class Recipient implements User { private static final String COUNTRY = "KOREA"; @Override public void printType() { System.out.println("수취인입니다."); } // 추가로 메서드 구현 public void printCountry() { System.out.println("국가는 " + COUNTRY + "입니다."); } } public class Main { public static void main(String[] args) { User user = new Recipient(); user.printType(); // "수취인입니다." user.printCountry(); // 호출이 불가능합니다. // Recipient recipient = (Recipient) user; recipient.printType(); // "수취인입니다." recipient.printCountry(); // "국가는 KOREA입니다." } }
- 객체 타입 변환(instancOf)
- 위 강제 타입 변환은 구현 객체가 인터페이스 타입으로 변환되어 있는 상태에서 가능합니다
User user = nwe Recipient();
User user = new Recipient(); Sender sender = (Sender) user; // 에외 발생
- instanceof를 사용하면 강제타입 변환에 앞서서 예외를 방지할 수 있게 됩니다.
User user = new Recipient(); if( user instanceof Recipient ) { // user 변수에 담긴 객체가 Recipient 타입이면, Recipient recipient = (Recipient) user; }
👨👩👦 인터페이스의 상속
- 인터페이스도 다른 인터페이스를 상속할 수 있다. 클래스는 다중상속을 허용하지 않지만, 인터페이스는 다중상속을 허용한다.
public interface child1 extends present1, presnet2 { ... }
- 하위 인터페이스를 구현하는 구현 클래스에서는 “하위 인터페이스의 추상 메서드"와 “상속하는 모든 상위 인터페이스의 추상 메서드"의 실체 메서드로 구현해야 한다.
하위인터페이스 변수 = new 구현클래스(); 상위인터페이스1 변수 = new 구현클래스(); 상위인터페이스2 변수 = new 구현클래스();
- 하위 인터페이스는 하위인터페이스, 상위1, 상위2 인터페이스의 실체 메서드를 모두 사용할 수 있다.
- 상위1 인터페이스는 상위1 인터페이스의 메서드만 사용이 가능하다.
- 상위2 인터페이스는 상위2 인터페이스의 메서드만 사용이 가능하다.
public interface InterfaceA { public void methodA(); } public interface InterfaceB { public void methodB(); } public interface InterfaceC extends ItnerfaceA, InterFaceB { public void methodC(); } public class ImplementationClassC implements InterFaceC { public void methodA() {...} public void methodB() {...} public void methodC() {...} } psvm { ImplementationClassC implC = new ImlimentationC(); InterfaceA iA = implC; iC.methodA(); // OK iC.methodB(); // NO iC.methodC(); // NO InterfaceB iB = implC; iC.methodA(); // NO iC.methodB(); // OK iC.methodC(); // NO InterfaceC iC = implC; iC.methodA(); // OK iC.methodB(); // OK iC.methodC(); // OK }
🤖 인터페이스 디폴트 메서드와 확장
디폴트메서드가 만들어진 이유
- 디폴트 메서드는 인스턴스의 메서드이다. 즉 구현 객체가 있어야 사용할 수 있다.
- 인스턴스 메서드가 왜 인터페이스에 있을까?
- Java8에서 인터페이스에서 디폴트 메서드를 허용하는 이유는 기존 인터페이스를 확장해서 새로운 기능을 추가하기 위해서이다.
- 만약 기존 인터페이스에 새로운 메서드를 추가하게 된다면? 해당 인터페이스를 구현하는 클래스를 모두 찾아서 구현 메서드를 작성해줘야 하며 작성을 해주지 않는다면 컴파일 에러가 발. 하게 된다.
- 하지만 인터페이스에 디폴트 메서드를 선언하게 되면 이미 선언된 인스턴스 메서드에 실체 메서드를 선언하지 않아도 문제없이 필요한 곳에서 디폴트 메서드를 사용할 수 있다.
- 디폴트 메서드는 즉 추상 메서드가 구현 클래스에서 실체 메서드로 구현되어야 한다는 제약을 없애준 편의 메서드로 볼 수 있다.
🧑🏻⚖️ 결론
- 인터페이스는 객체지향 프로그래밍을 돕는 디자인 패턴이기에 사용해서 구현하자로 말할 수 있다.
- 인터페이스를 구현하고, 상속하고, 확장하면서 얻을 수 있는 프로그래밍의 장점을 다형성과 사용하면서 유지보수에 있어서 기존의 코드 변경 없이 해당 구현 객체를 변경하기만 해도 호출되는 소스의 내용을 바꿔줄 수 있다.
- 보통 클래스의 상속보다 추상 클래스와 인터페이스를 이용해서 공통된 메서드를 구현하고, 다형성을 이용한다. 그 이유는 클래스 간 강한 결합도를 낮추기 위함이며 응집도를 높이고 결합도를 낮추는게 객체지향이 추구하는 기본 원칙이기 때문이다.