본문 바로가기
My Image
프로그래밍/Java

[JAVA] 자바 인터페이스란?(Interface)_이 글 하나로 박살내자

by Lim-Ky 2019. 12. 10.
반응형

1. 인터페이스 개념과 역할

 

인터페이스....이 글하나로 박살내자. (회사에서 존댓말을 많이 쓰기때문에 여기서라도 반말로 글을 써보고 싶음 ㅎ)

인터페이스는 뭘까?? 결론부터 말하면, 극단적으로 동일한 목적 하에 동일한 기능을 수행하게끔 강제하는 것이 바로 인터페이스의 역할이자 개념이다. 조금 더 유식하게 말하면, 자바의 다형성을 극대화하여 개발코드 수정을 줄이고 프로그램 유지보수성을 높이기 위해 인터페이스를 사용한다. 자 이게 무슨말인가? 바로 예시 들어간다.

 

교수님이 학생들에게 논문을 쓰라고 했다.

 

A학생은 PPT로 논문을 11일날 제출했다.

B학생은 EXCEL 2016 로 논문을 12일날 제출했다.

C학생은 EXCEL 2019 로 자기만의 색깔을 입혀 표 형식으로 12일날 제출했다.

D학생은 메모장에 '논문'을 쓰고 교수님이 말해준 당일 바로 제출했다.

 

응?? 논문을 쓰라고 지시했지만, 결과물이 너무 개성이 넘친다....이건 평가할 수 없을 것 같다. 왜 이런일이 일어날까?

가이드 라인 또는 어떠한 규격이 없기 때문에 발생하는 문제이다.

따라서 교수는 다시 명확한 가이드라인 있는 논문을 쓰라고 지시해야한다. 아래처럼...

 

학생들에게 2019.12.12일 18:00까지 홈페이지 본인 교수 홈페이지 제출란을 통해 논문을 제출해야하고

논문 파일 형식은 .PPT이며 10Page 안에 작성을 해야하고 논문 주제는 '블록체인을 활용한 공인인증서' 이다.

 

자 이번에 서울시는 밤길 여성들의 안전한 귀가를 위해 30억을 투입해 1000개 유명 중국 H사의 CCTV를 설치했다고 치자. 이제 CCTV에서 송출되는 영상을 각 지역 관할 파출소나 경찰서에서 모니터링 할 수 있도록 1년에 걸쳐 10억을 투자해 CCTV 모니터링 프로그램 시스템을 구축했다. 근데,, 문제가 생겼다 H사의 CCTV는 배터리가 불량고 비가 오면 방수처리가 잘 안되어 고장이 나기 시작했다.. 안되겠다 국산 G사의 CCTV로 전부 다 교체하기로 했다. 그런데 맙소사..중국 H사 CCTV의 영상 송출 모듈에만 특화된 프로그램을 만든 것이다. 다시 프로그램을 만들고 시스템을 구축해한다..응?

감이 올 것이다.

 

만약 현재 시중에서 판매되고 있는 CCTV 제조사가 CCTV의 송출 모듈을 모두 공통적으로 규격에 맞는 모듈로 개발했다면 이런 유지보수성의 불편함은 발생되지 않을 것이며 호환성이 높아질 것이다. 정리하면, 제조사가 다른 CCTV여도 영상 송출이라는 동일한 기능을 제공하게 하는 것이 바로 인터페이스이다.

 

자 이제 인터페이스의 개념을 정리하자!

 

인터페이스란? 극단적으로 동일한 목적 하에 동일한 기능을 보장하게 하기 위함!

어떻게? 자바의 다형성을 이용하여  개발코드 수정을 줄이고 유지보수성을 높인다!

 

반응형

2. 인터페이스 문법과 다형성 이해

 

자.. 이제 인터페이스가 어떤 놈인지는 알았고 실제 문법과 코드를 통해 이해해보자.

인터페이스는 interface 키워드를 통해 선언할 수 있으며 implements 키워드를 통해 일반 클래스에서 인터페이스를 구현할 수 있다.

 

또한, JAVA8 이전까지는 상수, 추상메소드만 선언이 가능하지만,

(상수, 추상메소드만 가능케했다는 것을 통해 그만큼 강제성이 강했다는 것을 유추할 수 있다.)

JAVA8부터 디폴트메소드, 정적메소드가 추가되었다.

(디폴트메소드, 정적메소드를 통해, 구현 강제성 안에 유연함을 심었다고 우선 이해하자)

 

왜 추가되었는지는 아래에서 따로 설명하고 우선 인터페이스에선 4가지를 정의하거나 구현할 수 있다.

 

public interface 인터페이스명 {

 

//상수

타입 상수명 = 값;

 

//추상 메소드

타입 메소드명(매개변수, ... );

 

//디폴트 메소드

default 타입 메소드명(매개변수, ... ){

  //구현부

}

 

//정적 메소드

static 타입 메소드명(매개변수) {

  //구현부

}

 

}

 

그럼 각각 어떤 의미가 있는지 직역해보자.

 

상수 : 인터페이스에서 값을 정해줄테니 함부로 바꾸지 말고 제공해주는 값만 참조해라 (절대적)

추상메소드 : 가이드만 줄테니 추상메소드를 오버라이팅해서 재구현해라. (강제적)

디폴트메소드 : 인터페이스에서 기본적으로 제공해주지만, 맘에 안들면 각자 구현해서 써라. (선택적)

정적메소드 : 인터페이스에서 제공해주는 것으로 무조건 사용 (절대적)

 

참고로 절대적이란 정말 아무것도 손댈 수 없음을 의미하고, 강제적이란 그래도 인터페이스를 implements하지 않으면 피할수는 있기에 강제적이라고 표현했다. 강제성이 있다고 해서 절대적인 것은 아니니.....

 

이제 아래 실제 코드를 보면서 자연스럽게 이해해보자.

 

하나의 예를 들어보겠다. 대한민국에서 은행 사업을 하려면, 금융결제원에서 정의한 어떠한 가이드를 따라야한다고 치고, Bank 라는 이름으로 인터페이스를 만들었다.

이제 어느 은행이든 은행 시스템은 운영하려면 Bank라는 인터페이스 가이드에 맞게 구현해야한다.

인출메소드, 입금메소드는 각 은행에서 오버라이딩 해서 재구현을 해야하며 블록체인 인증 메소드는 무조건 금융결제원에서 제공해주는 메소드를 사용해야 한다. 따라서 정적메소드로 구현하여 오버라이딩을 할 수 없게 만들었다. (그냥 가져다가 쓰라는 소리)

public interface Bank {

	//상수 (최대 고객에게 인출해 줄 수 있는 금액 명시)
	public int MAX_INTEGER = 10000000;
	
	//추상메소드(인출하는 메소드)
	void withDraw(int price);
	
	//추상메소드(입금하는 메소드)
	void deposit(int price);
	
	//JAVA8에서 가능한 defualt 메소드(고객의 휴면계좌 찾아주는 메소드 : 필수구현은 선택사항)
	default String findDormancyAccount(String custId){
		System.out.println("**금융개정법안 00이후 고객의 휴면계좌 찾아주기 운동**");
		System.out.println("**금융결제원에서 제공하는 로직**");
		return "00은행 000-000-0000-00";
	}
	
	//JAVA8에서 가능한 정적 메소드(블록체인 인증을 요청하는 메소드)
	static void BCAuth(String bankName){
		System.out.println(bankName+" 에서 블록체인 인증을 요청합니다.");
		System.out.println("전 금융사 공통 블록체인 로직 수행");
	}
		
	
}

그런데 여기서 디폴트 메소드에 대해서 생각해보자. 도대체 디폴트 메소드는 무엇일까? 하나의 예시를 들어보겠다.

 

금융결제원에서 이미 인터페이스를 각 은행사에 가이드 하였고 정상적으로 서비스가 되고 있는데 갑자기 금융 트렌드가 바뀌면서 고객의 휴면계좌를 찾아주는 서비스를 정부에서 점진적으로 도입하라고 지시를 하였다면.. 어떤일이 벌어질까??

 

추상메소드를 그냥 추가해서 다시 가이드 하면 되지 않을까?? 라고 생각했지만 쉽지 않다. 왜냐...각 은행사마다 개발환경 및 운영환경이 다르고, 휴면계좌 찾아주기 신규 프로세스를 도입하는데 있어 은행사마다 개발기간이 모두 상이하기 때문에 조금은 러프한 메소드를 추가해줘야 한다. 즉, 만약 추상메소드를 인터페이스에서 추가한다면, 이를 implements한 모든 클래스에서 강제적으로 추상메소드를 구현해야하고 구현하지 않을시 전부 에러가 난다. 

 

하지만 디폴트 메소드를 정의하고 기본 구현부를 제공하고 만약 기본 구현부가 맘에 들지 않으면 각자가 오버라이딩을 하여 재구현할 수 있도록 선택적인 메소드를 가이드한다면 시스템 운영 유지보수성이 확보가 될 것이다.

이를 더 쉽게 말하면, 결국 이미 운영되고 있는 시스템에서 추가 요건으로 인해 불가피하게 반영을 해야할 때 디폴트메소드를 쓰면 효과적이란 소리다.

 

자 이제 KB은행, SH은행은 규격화 된 Bank 인터페이스를 통해 각자에 맞는 스타일대로 은행 인출/입금 서비스를 제공한다. 아래 코드를 보자.

public class KBBank implements Bank{

	@Override
	public void withDraw(int price) {
		System.out.print("KB은행만의 인출 로직...");
		if(price < Bank.MAX_INTEGER){
			System.out.println(price+" 원을 인출한다.");	
		}else{
			System.out.println(price+" 원을 인출실패.");	
		}
	}

	@Override
	public void deposit(int price) {
		System.out.println("KB은행만의 입금 로직..."+price+" 원을 입금한다.");
	
	}

}

KB은행은 휴면계좌 찾아주기 메소드를 재구현하지 않았다. 즉 금융결제원이 제공해주는 메소드를 사용하겠다는 뜻이거나 혹은 아직 사용하지 않겠다라고 이해하면 된다.

public class SHBank implements Bank{

	@Override
	public void withDraw(int price) {
		System.out.println("SH은행만의 인출 로직...");
		if(price < Bank.MAX_INTEGER){
			System.out.println(price+" 원을 인출한다.");	
		}else{
			System.out.println(price+" 원을 인출실패.");
		}
	}

	@Override
	public void deposit(int price) {
		System.out.println("SH은행만의 입금 로직..."+price+" 원을 입금한다.");
		System.out.println("SH은행은 별도의 후행처리 작업을 따로 한다.");
	
	}
	
	//JAVA8에서 가능한 defualt 메소드(고객의 휴면계좌 찾아주는 메소드)
	@Override
	public String findDormancyAccount(String custId){
		System.out.println("**금융개정법안 00이후 고객의 휴면계좌 찾아주기 운동**");
		System.out.println("*SH은행만의 로직 적용*");
		return "00은행 000-000-0000-00";
	}

}

 하지만 SH은행은 휴면계좌 찾아주기 메소드를 재정의하여 SH은행사 만의 휴면계좌 찾아주기 로직을 재구현했다. 

 

public class KakaoBank{

	public void kakaoWithDraw(int price) {
		System.out.print("Kakao은행만의 인출 로직...");
		System.out.println(price+" 원을 인출한다.");	
	}

	public void kakaoDeposit(int price) {
		System.out.println("Kakao은행만의 입금 로직..."+price+" 원을 입금한다.");
	}
	
	public void kakaoFindDormancyAccount(){
		System.out.println("kakao은행만의 휴면계좌 찾아주기 로직");
	}

}

마지막으로 아래 신규 인터넷 은행사 카카오뱅크 코드를 보자. 위 코드에서 볼 수 있듯이 카카오뱅크는 인터페이스를 implements를 하지 않은 채 자신만의 메소드를 구현했다. 어떤 문제점이 있을까? 당연...금융결제원에서 제공해주는 그 어떠한 서비스도 사용할 수 없으며 호환성이 없으며 연동이 불가할 것이다. 

 

아래 메인 소스를 보면, bank = new kakaoBank(); 부분에서 type mismatch 에러가 날 것이다.

또한, 자바의 다형성을 극대화 하여 개발 코드 수정을 줄일 수 있다고 했는데 어떤부분에서 가능한 것일까?

만약 이 메인함수가 특정 대학교에 등록금 인출, 입금 등의 업무와 관련있는 소스라고 하자. 대학교는 간혹 등록금 납부 주관 은행을 교체하기도 한다. 물론 가상계좌를 통해 납입하지만 주은행을 변경하게 되면 대학교 등록금 납부 시스템에

기존은행에서 교체할 은행으로 변경을 해줘야한다.

 

이럴 경우 간단하게 인스턴스만 바꾸면 호환성이 보장된 상태에서 동일한 기능을 수행할 수 있을 것이다. 물론 해당 소스에서 보면, 금액, 고객ID, 은행명 등 하드코딩이 들어가 있지만 예시니까 이해해 주시길.....^^;;

 

public class Main {

	public static void main(String[] args) {
		
		Bank bank = new KBBank();
		bank.withDraw(100);
		bank.deposit(100);
		bank.findDormancyAccount("763231");
		Bank.BCAuth("KBBank");
		
		System.out.println("\n*************인스턴스 교체!!***************\n");
		
		bank = new SHBank();
		bank.withDraw(100);
		bank.deposit(100);
		bank.findDormancyAccount("4311");
		Bank.BCAuth("SHBank");
		
		System.out.println("\n*************카카오은행 연동 실패!!***************\n");
		//호환성 불가
		/*
		bank = new KakaoBank();
		bank.withDraw(100);
		bank.deposit(100);
		bank.findDormancyAccount("4311");
		*/
		
		System.out.println("\n*************대학교 주은행  교체!!***************\n");
		
		bank = new KBBank(); //new KBBank();
		bank.withDraw(20000);
		bank.deposit(1000);
		bank.findDormancyAccount("855512");
		Bank.BCAuth("SHBank");

	}

}

 

 카카오뱅크 부분을 제거하고 수행하면 아래와 같은 결과를 얻을 수 있다.

 

 

자 오늘 인터페이스에 대해서 알아보았다.. 정리하면 인터페이스는 추상메소드와 상수를 통해 강력한 강제성을 가지게 하여 인터페이스를 implements한 클래스가 동일한 동작을 수행하도록 보장한다. 또 JAVA8 부터 디폴트 메소드를 허용하면서 추가요건에 대한 대처를 할 수 있도록 유연성을 확보해주었다. 아무튼 인터페이스에 대해서 글을 마무리하고..

다음 이시간엔 인터페이스와 추상클래스의 궁극적인 차이점에 대해서 이야기해볼까한다....

 

도움이 되셨다면 댓글과 좋아요 부탁드립니다~ 큰 힘이 됩니다! ^^

 

 

 

반응형

댓글