👩‍💻 BackEnd/☕️ 자바 [Java]

[Java] 자바의 정석 : 인터페이스의 장점

minhe2810 2024. 2. 27. 15:04

인터페이스의 장점

  • 두 대상(객체) 간의 연결, 대화, 소통을 돕는 '중간역할'을 한다. 
  • 선언(설계) 와 구현을 분리시킬 수 있게 한다. 
  • 인테페이스 덕분에 B 가 변경되어도 A는 안바꿀 수 있게 된다. (느슨한 결합) 
  • 개발 시간을 단축할 수 있다. 
  • 변경에 유연한 설계가 가능하다. 

 

기계와 소통하기 쉽도록 도와주는 역할을 해줌. 기계의 껍데기 

 

인터페이스가 왜 필요한지 어떤 장점이 있는지 이해가 갈 것이다. 

 

컴퓨터 하드웨어를 사람이 직접 다루려면 쉽지 않음. 서로 사용하는 언어가 다르기 때문 

 

따라서 gui 가 나옴 graphic  user interface -> 이또한 껍데기 

다른 하드웨어로 바뀌어도 인터페이스만 바뀌지 않으면 계속해서 사용할 수 있음. 

 

즉, 변경에 유리하다. 

 

이런게 인터페이스의 장점이다. 

 

선언부만 떼어내어서 인터페이스에 추상메서드로 정의를 해둔다. 

그리고 해당 인터페이스를 구현하도록 만든다. 

껍데기 + 알맹이가 붙어있었던 것을 -> 유연하지 않고 변경에 불리함.  

인터페이스 안에 구현체를 둠으로 써 두 가지를 분리함. -> 알맹이를 다른 것으로 변경할 수 있음. 변경에 유리함. 

 

따라서 인터페이스 덕분에 B가 변경되어도 A는 안바꿀 수 있게 된다. (느슨한 결합) 

 

예제 살펴보기 

package pkg2;

class A{
    public void method(B b) {   // 변경 필요 2 
       	b.method(); 		// 변경 필요 3
    }
}

class B{
    public void method() {
        System.out.println("B 클래스의 method 호출");  
    }
}

class C{
    public void method() {
        System.out.println("C 클래스의 method 호출");
    }
}

public class InterfaceTest {
    public static void main(String[] args) {
        A a = new A();  
        a.method(new B());   // 변경 필요 1 
    } 
}

 

  • Class A 에서 매개변수로 B 클래스를 받아 실행하는 메서드를 선언한뒤, InterfaceTest 클래스에서 A 클래스의 인스턴스 생성 후 method() 를 호출한다. 
    1. 이 경우는 A클래스 하나에 method 의 선언부와 구현부가 모두 합쳐져 있는 상태임. 
    2. 따라서 만약에 B 클래스를 C 클래스로 변경해야하는 경우가 생긴다면 변경해줘야 할 부분이 주석에 보이는 곳들이다. 
    3. 변경해줘야 할 부분이 별로 많아보이진 않지만 만약 코드가 더 복잡할 경우 더 어려워질 것이라 예상된다. 

 

 

그럼 이제 인터페이스를 활용하여 코드를 개선해보자. 

만일 클래스 B를 더이상 사용하지 않고 클래스 C로 변경하는데 인터페이스를 활용한다면 

 

코드의 선언부를 인터페이스에 선언을 하고 클래스에 implement I 를 하여 인터페이스를 구현하면 된다. 

그러면 Class A 의 코드를 수정하지 않아도 Interface I 를 구현한 클래스는 모두 매개변수로 받아들일 수 있게 된다. 

그렇다면 변경해줘야 할 부분은 

package pkg2;

class A{ // interface I 를 구현한 클래스라면 변경 해주지 않아도 됨. 
    public void method(I i) { 
        i.method();
    }
}

// B 클래스의 선언과 구현을 분리 
interface I{
    void method();
        }

class B implements I{
    public void method() {
        System.out.println("B 클래스의 method 호출");
    }
}

class C implements I{
    public void method() {
        System.out.println("C 클래스의 method 호출");
    }
}

public class InterfaceTest {
    public static void main(String[] args) {
        A a = new A();
        a.method(new C());  // 변경 부분 1 : A가 B를 사용(의존) 
    }
}

 

  • 이렇게 변경할 부분이 적어진다. 
  • Class C에도 implement 를 작성해야하지만 이건 클래스 생성 시 할 일이므로 뭐... 포함을 안시켜도 되지 않을까? 
  • 그럼 한 번이다! 히히

여기서 중요한 포인트는 적절히 구현 클래스를 선언만 해준다면  Class A에는 코드 변경 없이 다야한 클래스를 불러와 사용할 수 있게 되기 때문에 인터페이스를 활용하는 것이 조금 더 유연해질 수 있다. 이게 포인트라고 한다.

 

이렇게 인터페이스의 장점을 알게 되었다. (변경이 적을 수록 실수를 줄일 수 있기 때문에 훨씬 좋은 방식임을 알 수 있다) 

 


그 밖의 인터페이스의 장점은 다음과 같다. 

 

✅ 개발 시간을 단축할 수 있다. 

추상 메서드 호출 가능 

 

메서드가 완성되어있다고 가정 하에 호출하여 사용할 수 있다. 

 

추상 메서드 말고 iv 는 어떻게 사용하죠? 

iv 직접 접근은 불가 . iv 는 private으로 해두고 method를 통해서만 접근이 가능 하기 때문임. 

 

✅ 변경에 유리한 설계가 가능하다. 

 

✅ 표준화가 가능하다. (JDBC)

jdbc 

데이터 요청하여 데이터를 받아올 수 있는데 

데이터 베이스의 종류가 변경이 되면 애플리케이션도 변경을 많이 해야한다. 

그래서 이를 중간에 인터페이스 두듯이 jdbc(interface 의 집합) 를 두게 된다. 

표준을 만들어서 회사에 줌. 회사에서 jdbc 인터페이스에 맞춰서 개발을 한다. 

jdbc 가 바뀌지 않는 한 애플리케이션을 바꾸지 않아도 됨. 

대신 데이터 베이스 회사가 jdbc 표준에 맞게 개발을 해줘야 한다. 

각 회사의 기능에 의존하는 게 아닌 표준에만 의존하면 됨. 

 

인터페이스를 이용해서 표준화 한 것 

 

✅ 서로 관계없는 클래스들을 관계를 맺어줄 수 있다. 

예를 들어 Unit 클래스 아래에 지상unit , 공중 unit 이 있고, 그 하위에, 지상 unit 에는 병사, 탱크, 로봇이 있고, 공중 unit 에는 수송선 이 있다고 할때 기계를 고치는 메서드를 작성하려고 하면 무엇으로 묶어야 할까? 지상 unit은 병사가 있기 때문에 지상 unit으로 묶는 것은 부적절 하다. 또한 수송선은 공중 unit 이기에 이를 포함시키지 못하기 때문에 적절하지 않다. 

 

이때 인터페이스를 활용할 수 있을 것이다. 

 

repairable 인터페이스를 선언하고 

그 안에 추상 메서드로 repair 메서드를 선언하는 것이다. 

그리고 나서 탱크, 로봇, 수송선 클래스에 각각 repairable 인터페이스를 구현하도록 하면 

추상 메서드의 매개변수로 repairable 를 받아오면 해당 유닛들을 인터페이스로 관개를 맺어줄 수 있다.! 

package pkg2;

interface Repairable{
    void repair(Repairable r);
}

class Tank1 implements Repairable{

    @Override
    public void repair(Repairable r) {
        
    }
}

class Dropship3 implements Repairable{

    @Override
    public void repair(Repairable r) {
        
    }
}

class Robot implements Repairable{

    @Override
    public void repair(Repairable r) {
        
    }
}
public class RepairClass {
}

 

  • 이렇게 Repairable 인터페이스를 생성한 뒤 각각의 수리가 필요한 클래스를 Repairable 인터페이스를 구현하도록 하면 각각의 관계 없는 클래스를 관계를 맺도록 설정할 수 있다. 
  • 또한 각각의 클래스에 맞게 메서드를 오버라이드해서 특성에 맞게 다르게 구현할 수 있다.