관리 메뉴

나구리의 개발공부기록

자바의 정석 기초편 ch7 - 39 ~ 41[인터페이스의 장점, 인터페이스의 디폴트메서드] 본문

유튜브 공부/JAVA의 정석 기초편(유튜브)

자바의 정석 기초편 ch7 - 39 ~ 41[인터페이스의 장점, 인터페이스의 디폴트메서드]

소소한나구리 2023. 11. 29. 17:35

1) 인터페이스의 장점 1

  • 두 대상(객체)간의 중간 역할을 함 (연결, 대화, 소통)
  • 선언부(설계, 껍데기)와 구현부(알맹이)를 분리시킬 수 있음

(1) 직접적인 관계의 클래스 

  • A a = new A();로 객체 생성 후 a.method()에 B의 객체를 인자로 입력하여 호출하면 B클래스의 메서드는 출력이 됨
  • 그러나 C의 객체를 인자로 출력하려고하면 A클래스에 있는 method()를 C클래스를 파라미터로 오버로딩해야 함, 즉 A의 코드의 수정이 불가피함
class A {	// C클래스의 메서드를 출력하면 클래스 A의 수정이 불가피함
	public void method(B b) {	// 클래스 B의 메서드 실행
		b.method();	// 메서드 호출
    }

	// 클래스 C의 메서드를 실행하는 메서드를 오버로딩 해야함
//	public void method(C c) {
//		c.method();	
//    }
}

class B{
	public void method()  {
		System.out.println("B클래스의 메서드");
    }
}

class C{
	public void method()  {
		System.out.println("C클래스의 메서드");
	}
}

public class InterfaceTest {
	public static void main(String args[]) {
		A a = new A();
		a.method(new B());	// A가 B를 사용(A가 B를 의존)
//		a.method(new C());	// A가 C를 사용하게 하려면?? 클래스 A를 수정해야함.
    }
}



(2) 간접적인 관계의(인터페이스사용) 클래스

  • 인터페이스 를 도입하여 추상 메서드를 만들고 클래스 B와 C가 해당 인터페이스를 구현하여 메서드를 각각 재정의
  • 클래스 A의 메서드의 매개변수로 인터페이스 타입을 지정하여 해당 인터페이스를 구현한 클래스를 인자로 메서드를 호출하도록 정의
  • 프로그램을 실행하는 main 메서드에서 A a = new A();로 객체를 할당 후 a.method()에 호출하는 인자만 수정하면 B와 C의 메서드를 호출 할 수 있음
  • 즉, 내부적인 로직을 건들지 않아도 메서드를 사용하는 쪽의 코드만 수정하여 여러 객체의 메서드를 접근할 수 있음 ->이는 나중에 웹애플리케이션 등을 개발할 때 유지보수에 매우 큰 장점을 가져다 줌
class A {	
	// 클래스를 수정하지 않아도 I인터페이스를 구현한 B,C클래스의 메서드를 모두 출력할 수 있음
	public void method(I i) {	// 인터페이스 타입을 매개변수로 메서드를 정의
		i.method();	
	}
}

interface I {	
	// B,C클래스 메서드의 선언과 구현을 분리 -> 선언부를 인터페이스에서 추상메서드로 제공
	public void method();
}

class B implements I {	// 인터페이스I를 구현
	public void method()  {
		System.out.println("B클래스의 메서드");
    }
}

class C implements I{	// 인터페이스I를 구현
	public void method()  {
		System.out.println("C클래스의 메서드");
	}
}

public class InterfaceTest {
	public static void main(String args[]) {
		A a = new A();
//		클래스 A를 수정하지 않고 해당 메서드를 호출하는 인자(객체)만 수정하면
//		클래스 B, C의 method()를 모두 출력할 수 있음
		a.method(new B());
		a.method(new C());
    }
}

2) 인터페이스의 장점2

  • 개발 시간을 단축 시킬 수 있음
  • 구현부가 완성되어있지 않아도 인터페이스를 활용(추상메서드호출)하여 구현부가 완성 되었다는 가정하에 코드를 작성할 수 있어 각각 모듈 단위로 개발을 하고 완성 시킬 수 있음
  • 변경에 유리한 유연한 설계가 가능함
  • 표준화가 가능(예시 - JDBC API; 인터페이스의 집합)
  • 데이터베이스업체를 바꾸려고 할 때 표준화(JDBC API)가 되어있으면 내부 로직의 코드의 변경없이 교체 가능
  • 서로 관계없는 클래스들을 관계를 맺어줄 수 있음

 

좌)Unit의 상속계층도, 우)서로 관련없는 클래스를 인터페이스를 활용해 관계를 맺음(Repariable 인터페이스)

(1) 예제

  • 상속계층도의 유닛 중 기계유닛을 수리하는 코드를 작성한다고하면? -> 종류마다 오버로딩 해야함.. 종류가 많아질수록 코드 중복
  • 조상 클래스를 활용 해보고자 하면? -> Marine클래스는 수리기능이 있으면 안되고, Dropship클래스는 수리기능이 빠짐
  • 상속 관계가 없는 클래스들을 인터페이스를 구현시켜 기계유닛이라는 새로운 관계를 형성시키고 간단한 코드만으로 추상 메서드를 정의한 기능을 각각 사용할 수 있음
void repair(Tank t) {
	// 탱크 수리 메서드
}

void repair(Dropshop d) {
	// 드랍쉽 수리 메서드
}

void repair(GroundUnit gu) {
	// 그라운드유닛을 수리 메서드
}

// 인터페이스를 통해 관계없는 클래스들을 관계를 형성
interface Repairable {}	// Repairable 인터페이스생성

// Repairable를 구현한 클래스들 -> 공통점이 생김
class SCV extends GroundUnit implements Repairable {
	// ...
}
class Tank extends GroundUnit implements Repairable {
	// ...
}
class Dropship extends AirUnit implements Repairable {
    // ...
}

// 오버로딩, 상속클래스들을 활용하지 않고 아래의 메서드 하나만으로 기계유닛(새로운 관계)의 수리를 구현
void repair(Repairable r) {	// Repairable을 구현한 클래스의 객체만 가능
	if (r instanceof Unit) {
    	Unit u = (Unit)r;
        while(u.hitPoint!=u.MAX_HP) {
        	u.hitpoint++;	// Unit의 HP를 증가시킨다
        }
    }
}

3) 인터페이스에 디폴트메서드와 static메서드 추가 가능 (JDK1.8 - Java 8 부터 적용)

(1) 인터페이스의 디폴트 메서드

  • 기존에 사용중인 인터페이스에 새로운 추상 메서드를 추가하기가 어려움이 있어 해결책으로 디폴트 메서드(default method)가 등장함
  • 접근제어자 default가 아님
  • 인터페이스에 새로운 추상 메서드를 추가하면 인터페이스를 구현하는 클래스에 전부 해당 메서드를 완성 시켜야하는데, 해당 인터페이스가 다양한 곳에 사용 될 수록 수정할 곳이 많아 졌음
  • 디폴트메서드는 인스턴스메서드이며 원래의 인터페이스의 원칙을 깨고 개념을 확장 시켰음
  • 디폴트메서드로 인하여 인터페이스에 직접 기능을 추가한 메서드를 제공함으로써 해당 인터페이스를 구현한 모든 클래스가 추가한 기능을 사용할 수 있게됨
  • 즉, 인터페이스에 선언된 디폴트메서드는 오버라이딩 하지 않고 그기능을 그대로 사용해도 됨

(2) 인터페이스의 스태틱 메서드

  • 인터페이스에 static 메서드를 정의할 때에도 메서드의 구현부를 작성하여 기능을 정의해 줘야함
  • 다만, 일반적인 인터페이스의 메서드들과 다르게 구현체의 클래스가아닌 인터페이스의 이름을 통해 메서드를 호출함
  • 오버라이딩이 불가능하며 구현클래스에 상속되지 않으므로 인터페이스의 구현체를 참조하고있는 참조변수로 스태틱 메서드를 호출할 수 없는 등의 차이가 있음
interface MyInterface {
	// 인터페이스가 구현 된 모든 클래스마다 새로운 추상메서드를 완성 시켜줘야함
	void method();
	void newMethod();	// 추상 메서드를 추가
    
	// 인터페이스의 static 메서드
	static void staticMethod() {
		/* 기능 구현 */
	}
}

interface MyInterface {
// 디폴트 메서드를 추가함으로써 인터페이스에서만 디폴트 메서드를 정의하면되고 클래스는 해당 디폴트클래스를 사용할 수 있음
	void method();
	default void newMethod() { /* 기능생략 */}	// 디폴트메서드(default 생략 불가)
}

 

(3) 디폴트 메서드가 기존의 메서드와 충돌할 때의 해결책

  • 그냥 직접 오버라이딩하면 대부분 해결 됨
  • 여러 인터페이스의 디폴트 메서드간의 충돌 -> 인터페이스를 구현한 클래스에서 디폴트 메서드를 오버라이딩
  • 디폴트 메서드와 조상 클래스의 메서드 간의 충돌 -> 조상클래스의 메서드가 상속 되며 디폴트 메서드는 무시 됨
  • 특정 상황에 따라 인터페이스의 디폴트 메서드를 직접 호출하는 것도 방법이 될 수 있음

 

** 출처 : 남궁성의 정석코딩_자바의정석_기초편 유튜브 강의