[JAVA] JAVA에서 Interface를 사용하는 이유

1. Cooperation (협업)

Interface 미 사용시

한국인을 위한 번역기를 업무를 분담하여 만든다고 가정하자. 아래와 같은 결과물이 나왔다.

팀원1 의 작업물

/**
 * @author 팀원1
 */
public class EnglishTrans {
  public String koreanToEnglish(String str) {
    //TODO: 한국어를 영어로 번역
  }
  public String englishToKorean(String str) {
    //TODO: 영어를 한국어로 번역
  }
}

팀원2 의 작업물

/**
 * @author 팀원2
 */
public class ChineseRendering {
  public String translateChinese(String str) {
    //TODO: 한국어를 중국어로 번역
  }
  public String translateKorean(String str) {
    //TODO: 중국어를 한국어로 번역
  }
}

개인의 개성이 적나라하게 반영되었다.

메서드명, 클래스명 모두 다르다. 번역 기능을 만드는 일도 벅차서, 새로 팀원을 영입해 “우리의 클래스들을 참조하여 화면에 제공할 API를 만들어줘”하고 시켰다. 새 팀원은 클래스명을 받고 개발을 시작했다.

EnglishTrans trans = new EnglishTrans();
String str = trans.koreanToEnglish(str);
// TODO: Business Login
...

ChineseRendering rendering = new ChineseRendering();
String str = rendering.translateChinese(str);
// TODO: Business Login
...




Interface 사용시

public interface Translation {
  // 한국어를 번역하다
  public String translate(String str);
  // 한국어로 번역하다
  public String translateInto(String str);
}

위는 공통적으로 implements할 인터페이스이다. 각자 만들 클래스에서 Translation 인터페이스를 implements 한다. 그럼 강제로 해당 메소드를 구현해야 한다.


각 팀원 1과 2의 작업물

/**
 * @author 팀원1
 */
public class EnglishTranslation implements Translation {
  @Override
  public String translate(String str) {
    //TODO: 한국어를 번역
  }
  @Override
  public String translateInto(String str) {
    //TODO: 한국어로 번역
  }
}
/**
 * @author 팀원2
 */
public class ChineseTranslation implements Translation {
  @Override
  public String translate(String str) {
    //TODO: 한국어를 번역
  }
  @Override
  public String translateInto(String str) {
    //TODO: 한국어로 번역
  }
}


아래는 호출하는 부분이다.

Translation trans = new EnglishTranslation();
String str = trans.translate(str);
// TODO: Business Login
...

Translation trans = new ChineseTranslation();
String str = trans.translate(str);
// TODO: Business Login
...

사용할 때 인터페이스를 이용해서 원하는 언어에 따라 클래스를 골라서 객체를 생성해서 쓰면 되고 통째로 로직을 북붙해서 재활용하기도 편하다.

물론 인터페이스를 만들지 않아도 서로 약속하고 맞출 수도 있지만 오타가 발생하거나 작업량이 많아지면 잊어버릴 수 있다.

굳이 협업이 아니더라도 위와 같은 구조를 가지고 가는 것이 좋겠다.




Easy to replace (교체 용이)

이번엔 암호화 기능을 개발한다고 가정한다.

public interface Crypto {
  // 암호화
  public String encrypt(String str);
  // 복호화
  public String decrypt(String str);
}

위와 같이 인터페이스로 표준을 잡고 아래와 같이 구현체를 개발한다.

public class SHA512Crypto implements Crypto {
  @Override
  public String encrypt(String str) {
    // TODO: SHA512 방식으로 암호화
  }
  @Override
  public String decrypt(String str) {
    // TODO: SHA512 방식으로 복호화
  }
}

SHA512 방식은 더 이상 안전하지 않는 것 같다. 다른 방식으로 바꾸고 싶다면 클래스를 개발해서 이름만 교체하면 된다.

교체할 때에는 객체를 생성하는 클래스만 변경해주면 아래의 로직은 일체 수정할 일이 없다.

Crypto crypto = new SHA512Crypto(); // 기존 SHA512 방식
String enc = crypto.encrypt("1234");
교체

Crypto crypto = new SuperPowerCrypto(); // 신규 개발한 암호화 방식
String enc = crypto.encrypt("1234");
1. Multiple inheritance (다중 상속)
 부분은 실제 자바에서 사용하고 있는 부분을 볼게요.

 

public class HashMap<K,V> extends AbstractMap<K,V>
  implements Map<K,V>, Cloneable, Serializable {
}

기본적으로 Map이니깐 Map 인터페이스를 구현했다. Cloneable로 인스턴스가 복제 가능하도록 하였고 Serializable로 직렬화했다. 기본적으로 CloneableSerializable은 구현할 필요없이 자바가 내부적으로 해준다.

필요한 인터페이스를 상속받아서 구현하면 여러 기능들을 구조적으로 포함할 수 있다.




결론

이외에도 인터페이스를 사용하는 여러 디자인 패턴이 있다. 상세히 알고 싶으시다면, 이 부분은 자바 디자인 패턴을 따로 공부하시면 된다.

인터페이스는 잘 사용하면 프레임워크나 배포되는 공용 컴포넌트, 유틸 등을 개발할 때 아주 효과적이다.

다만, 잘 사용해야된다.

반대로, 일반 웹 개발 프로젝트에서는 오히려 복잡도만 증대시키는 상황이 많다. 많은 사람들이 불편해하고 필요성을 못느낀다면 과감히 버리는게 맞다.

결론은? 잘 사용해야된다.

태그:

카테고리:

업데이트:

댓글남기기