추상 클래스와 인터페이스

동동·2022년 6월 3일
0

자바를 배우면서 가장 이해하기 힘들었던 개념중에 추상 클래스와 인터페이스의 차이였다.
둘다 비스무리 한데 생긴건 다르네!? 처음엔 그냥 느낌적인 느낌으로 구분해서 사용하다가 며칠전 회사에서 어떤 분이 추상클래스와 인터페이스의 차이에 대해 물어보게되었고, 이를 설명한 내용을 정리 하고자 한다.

보통 추상 클래스와 인터페이스의 설명을 보면 문법적인 차이를 설명하지만 사실 문법은 언어마다 조금씩 다르고 나도 가끔 헷갈리면 그냥 인터넷으로 찾아 사용한다. 중요한건 문법이 아니고 이것에 대한 개념과 왜 사용하는지 아는것이다.
(하지만 여기서 쓰이는 예시는 java 로 되어 있다)

별다방 이야기

대한민국의 별다방이라는 어느 카페가 있다. 이 별다방은 처음 작은 카페로 시작하게 되었지만 맛있는 커피맛과 카페 특유의 분위기로 입소문을 타게 되었고 점차 지점을 늘리고 확장하게 되었다. 이 별다방의 확장을 프로그래밍 해보자

추상 클래스

별다방의 아메리카노는 다른 카페와는 다른 오묘하고 고소한 커피맛으로 유명하다. 원두를 로스팅 하고 추출하는 방법에서 다른 카페와는 다른 방식을 가지고 있다. 별다방 사장님은 지점을 확장하면서 처음 2호점을 냈을 땐 바리스타를 뽑아서 직접 커피 만드는 법을 가르쳐줬다. 그런데, 점점 지점이 많아지면서 일일이 교육하기 힘들어졌다. 같은 일을 하는 것을 일일이 가르치는건 너무 비효율이였기 때문이다. 그래서 사장님은 커피 만드는 레시피를 만들어서 지점에 나누어 주였다.

클래스와 상속

위 상황을 프로그래밍 하면 어떻게 될까?
일단 별다방이라는 하나의 브랜드는 모든 지점에 모티브가 되기에 추상 클래스로 만들 수 있다.

abstract class StarCafe {}

그리고 별다방의 각 지점은 이 추상 클래스를 상속 받아서 만들 수 있다.

class StarCafeSeoul extends StarCafe {}
class StarCefeBusan extends StarCefe {}

이렇게 별다방 지점이 만들어졌고 별다방에서는 동일한 아메리카노 만드는 법을 각 지점에 나누어 주어야 한다.
여기서 동일한 이란 말이 중요하다. 각 지점에서 아메리카노는 기본이 되기에 필수로 들어가는 메뉴이다. 그리고 각 지점에서 만드는 커피의 레시피가 동일하다면 이 것을 별다방 본사, 즉 부모 클래스에서 정의할 수 있다.

abstract class StarCafe {
	americano makeAmericano () {
    	return '맛있는 아메리카노';
    }
}

어? 그런데 저건 그냥 메소드인데? 추상 클래스에서는 추상 메소드를 사용해야 하는거 아닌가?
그렇다. 저렇게 사용한다면 굳이 abstract 를 사용할 필요가 없이 부모 클래스를 만들면 된다.
그렇다면 추상 메소드는 언제 어떻게 사용해야 할까?

추상 메소드

별다방이 너무 유명해졌다. 이제 대한민국이 아닌 전세계로 진출하게 되었다. 유럽에 진출한 별다방! 그런데 사장님은 고민에 빠졌다. 유럽에서는 대한민국과 문화가 달라 커피 마시는 방법이 조금 달랐다. 대한민국에서 최고의 인기를 달리는 아이스 아메리카노! 하지만 밀라노에서는 아이스 아메리카노에 얼음이 없다!!! 사장님은 애초에 전세계 각국의 지점마다 색다른 레시피를 전부 파악해서 별다방을 만들지 않았다. 하지만 아메리카노는 전세계 어디에서나 마시는데?!?

그래서 추상 메소드를 정의한다.
일단 클래스는 만들었지만 어떻게 쓰이는지 상세할 필요는 없다. 각 지점에서 커스텀해서 아메리카노를 만들겠지만 일단 아메리카노는 기본이기에 추상 메소드로 정의해서 어디에서나 아메리카노를 마실 수 있게 한다. 그리고 상속 받은 자식 클래스에서 해당 추상 클래스를 상세한다.

abstract class StarCafe {
    abstract iceAmericano makeIceAmericano ();
}

class StarCafeSeoul extends StarCafe {
	iceAmericano makeIceAmericano () {
    	return '얼음 추가된 아이스 아메리카노';
    }
}

class StarCafeMilano extends StarCafe {
	iceAmericano makeIceAmericano () {
    	return '얼음 없는 아이스 아메리카노';
    }
}

추상 클래스와 추상 메소드를 사용하는 이유

클래스 상속의 장점은 동일한 기능을 중복 없이 사용 할 수 있다는 것이다. 그리고 만약 변경이 있을 시 한 곳에서만 변경 해주면 된다. 하지만 위에서 처럼 각 지점에 맞게 커스텀 해야 하는 경우가 생길 수 있다. 하지만 별다방이 처음 시작할 밀라노 진출을 생각하지 못 했던거와 같이 최초 코드 설계시 미래의 어떤일이 있을지 모두 알고 설계 하지 않는다. 하지만 분명 확장성이 있는 부분이라면 추상화를 통해 확장성 있는 코드로 만드는게 좋다.

인터페이스

별다방이 전세계적으로 유명해졌다. 사장님은 행복한 나날이 계속 될 것이라 생각했습니다.
그런데!! 갑자기 코로나 대 유행이 일어났다!! 😱😱😱
카페에는 사람들이 오질 않았고 매출은 반토막이 났고 사장님은 깊은 고민에 빠졌다. 직원들과 밤낮을 지새며 아이디어 회의를 했고, 멋진 아이디어들을 생각했다.

  • 드라이브 스루를 만들어서 사람들이 비대면으로 커피를 사게 하자
  • 원격 주문으로 커피 배달을 시작하자

사장님은 직원들이 생각한 멋진 아이디어를 실행 하고자 했지만, 드라이브 스루를 만들자니 자동차가 대기 할 수 있는 넓은 대지가 필요했고, 배달을 하기 위해 라이더들을 고용해야 하기에 모든 지점에 적용하기 힘들었습니다. 그리고 어떤 지점은 코로나에도 굳이 드라이브 스루, 배달을 하지 않아도 매출이 괜찮았습니다. 결국 사장님은 각 지점 상황에 맞는 방법을 선별적으로 적용하였습니다.

결과는 대 성공! 고객들은 각 지점마다 어떤 주문 방식이 있는지 확인 이후에 해당 주문 방식을 통해 주문하면 맛있는 아메리카노를 마실 수 있었습니다.

인터페이스

직원들이 낸 아이디어는 인터페이스로 정의 할 수 있습니다.

interface DriveThrow {
	void DriveThrowOrder();
}

interface Online {
	void OnlineOrder();
}

그리고 지점마다 맞는 방식을 선별해서 도입할 수 있습니다.

class StarCafeSeoul extends StarCafe implements DriveThrow {
	void DriveThrowOrder() {
    	// 드라이브 스루 오더
    };
}

class StarCafeBusan extends StarCafe implements Online {
	void OnlineOrder() {
    	// 온라인 스루 오더
    };
}

class StarCafeNewYork extends StarCafe implements DriveThrow, Online {
	void DriveThrowOrder() {
    	// 드라이브 스루 오더
    };
    
    void OnlineOrder() {
    	// 온라인 스루 오더
    };
}

추상 클래스와 인터페이스 차이

추상 클래스는 인터페이스보다 좀 더 클래스의 근본을 정의 한다. 그리고 굳이 외부에 노출되지 않는 정보들의 상속을 정의 한다. 고객 입장에서는 아메리카노가 어떻게 만들어지는 알 필요가 없다. 고객들이 원하는건 맛있는 아메리카노가 지점마다 맛이 다르지 않고 제공되는 것이다. 그래서 굳이 아메리카노 레시피는 공개되지 않고 추상 클래스로 정의 된다.
하지만 인터페이스는 외부에 공개되는 정보들이다. 외부에서 내부의 서비스를 이용하기 위해 소통하는 방식을 정의 한다. 별다방과 고객이 소통하는 방식은 인터페이스로 정의 되어야 하고 별다방도 고객도 인터페이스만 바라보고 있으면 된다.

위 설명들이 잘 전달되었을지 모르겠지만, 일단 회사 사람들한테는 잘 전달되었다.
부족한게 있을지 모르겠지만 이해 되지 않거나 부족해서 첨부 되어야 하는 부분은 댓글로 부탁드립니다.

0개의 댓글