ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 두바이쫀득쿠키로 알아보는 추상화
    백엔드 : 서버공부/Spring 2026. 1. 9. 19:50
    728x90

    자바에서 인터페이스 이야기가 나오면 항상 듣는 말이있다.
     
    "확장성을 위해"
    "구현체의 교체"
    "다형성을 위해"
     
    그런데 막상 개발을 하다보면 이 인터페이스의 필요성을 잘 못느끼게된다. 
    좋다고는 하는데 괜히 코드량만 늘어나고, 코드도 직관적이지 않은 느낌이다. ( 인터페이스 좋음 라이팅당하는 느낌 ..)
     
    오랫동안 개발을 해온 사람들은 알겠지만 
    이 객체지향이라는 개념은 현실세계에서온 개념이다. 따라서 이럴때는 코드에서 벗어나 일상적인 상황으로 바꿔보는게 훨씬 이해가 쉽다.
     
    요즘 나름 핫한 두바이쫀득 쿠키를 예시로 인터페이스를 이해해보자!
     

    인터페이스는 객체를 바라보는 다양한 시각이다

    각 카페의 주방에서는 각자의 복잡한 방식으로 두쫀쿠를 만들지만 사먹는 우리 입장에서는 그런걸 알필요는 없다.
    우리에게 두바이쫀득쿠키는 메뉴일 뿐이다.
    그러나
    카페직원에게 두쫀쿠는 요리이다.
    카페직원이나 요리사는 두쫀쿠를 만들기 위해서 얼마나 많은 마시멜로를 넣고,
    카다이프 면을 넣어야하는지와 같은 복잡한 정보를 원한다.

    이분은 원하지 않았다만...

    다시 돌아와서 카페주인에게 두쫀쿠는 상품이다,
    그들은 마진률, 재료비와 같은 정보를 원한다.
     
    이렇게 카페에는 두쫀쿠를 바라보는 세가지 시선이 존재한다.
    이것을 자바로나타내면 아래와 같다.

    public class 두바이쫀득쿠키 implements 메뉴, 상품, 요리 {
    
        private String 이름;
        private List<재료> 재료목록;
        private int 가격;
    
        ....
    }

     
     

    public interface 메뉴 {
    
        String 이름();
        Long 가격();
    }

     

    public interface 상품 {
    
        int 마진률();
        int 재료비();
    }

     

    public interface 요리 {
    
        String 만드는법();
    }

     
     
    그리고 이것을 종합해서 표현하면 아래와 같다.

    public static void main(String[] args) {
    
        두바이쫀득쿠키 안성재_강정 = new 두바이쫀득쿠키();
    
        메뉴 두쫀쿠_메뉴판 =  안성재_강정;
        요리 두쫀쿠_조리법 = 안성재_강정;
        상품 두쫀쿠_상품 = 안성재_강정;
        
        // 손님
        두쫀쿠_메뉴판.이름();
        두쫀쿠_메판뉴.가격();
    
        // 카체 직원
        두쫀쿠_조리법.만드는법;
    
        // 카페 주인
        두쫀쿠_상품.마진률();
        두쫀쿠_상품.재료비();
    }

     
    우리가 이렇게 두쫀쿠하나를 가지고 여러시각에서 볼 수 있듯이
    프로그래밍에서도 같은 객체에 대해 서로 다른 시각으로 볼 수 있다.
     

    인터페이스는 여러구현체를 묶는 개념이다

    아마 지금부터 하려는 이야기는 앞선 이야기보다 좀 더 쉬울 것이다.
    우리가 인터페이스를 흔히 생각하고 주로 사용하는 관점이 이런 관점이기 때문이다.
     
    두바이쫀득쿠키 가게에 들어갔다고 생각해보자
     
    우리는 카페에 들어가서 메뉴판을 본다.
    메뉴판에는 이렇게 적혀 있다.
    "두바이쫀득쿠키"
    우리는 여기서 이런 것들을 전혀 신경 쓰지 않는다.

    • 이 쿠키가 잠실에서 만들어졌는지
    • 부천 공장에서 왔는지
    • 3분 동안 마시멜로를 녹이고 카다이프면 150g을 넣는지
    • 안성재 셰프가 만든 두바이 강정인지

    우리는 그냥 
    “두바이쫀득쿠키 하나 주세요” 이렇게 말한다.
    "3분 동안 마시멜로를 녹이고 카다이프면 150g을 넣은 두바이 쫀득쿠기 주세요" 라고 하지않는다.
    이 장면이 바로 인터페이스를 여러구현체를 묶는 개념으로 사용하는 관점이다.
     
    클래스가 양도 많고 복잡한 조리법 이라면 인터페이스는 한페이지도 안되는 가벼운 메뉴판이다.
     
    두바이쫀득쿠키를 만드는 과정은 복잡하지만, 우리는 그것을 "두바이쫀득쿠기"라고 호출한다.
     
    이것을 자바로 표현하면 아래와 같다.
     

    public interface 두바이쫀득쿠키 {
        void eat();
        void make();
    }

     
     

    public class 부천두쫀쿠 implements 두바이쫀득쿠키 {
        @Override
        public void eat() {
            System.out.println("부천에서 만든 두바이쫀득쿠키");
        }
        
        @Override
        public void make() {
            System.out.println("마시멜로 100그람 녹여서 오래오래....");
        }
    }

     
     

    public class 안성재두쫀쿠 implements 두바이쫀득쿠키 {
        @Override
        public void eat() {
            System.out.println("안성재가 만든 두바이쫀득쿠키");
        }
        
        @Override
        public void make() {
            System.out.println("아빠는 그렇게 안만들거야!!!!");
        }
    }

     
    우리는 구현체가 어떤지 알지 못한다.
    알 필요도 없다.
     
    또 조리법이 바뀌었다고 메뉴이름이 바뀌지도 않는다.
     

    public static void main(String[] args) {
    
        두바이쫀득쿠키 두쫀쿠 = new 안성재두쫀쿠();
        
        두쫀쿠.eat();
    }
    public static void main(String[] args) {
    
        두바이쫀득쿠키 두쫀쿠 = new 부천두쫀쿠();
        
        두쫀쿠.eat();
    }

     

    사용처는 끝까지 메뉴판만 본다

    사용처가 아는 정보는 딱 이것뿐이다.

    • 두바이쫀득쿠키라는 메뉴가 존재한다
    • 요청하면 하나 받을 수 있다

    어떻게 만들었는지는 전혀 중요하지 않다.
    이게 바로 추상화다.
     
    그런데 이 구조 어디서 많이 본 것같다.
     
    바로 자바의 컬렉션이다.

    List<String> list = new ArrayList<>();
    List<String> list = new LinkedList<>();

     
    우리가 실제로 여기서 사용하는 건 List다.
     

    List, ArrayList, LinkedList도 같은 원리다

    List는 메뉴판이다.
    ArrayList, LinkedList는 구현체다.
    우리는 보통 이렇게 말한다.
    “리스트 하나 주세요.”
    우리는 내부가 배열인지, 연결 리스트인지 신경 쓰지 않는다.
    중요한 건 이 동작들이다.

    List<String> list = new LinkedList<>();
    list.add("두쫀쿠");
    list.get(0);
     

     
    여기서 중요한 점은 인스터스를 왜 LinkedList<String> 으로 하지않고,  List<String> 으로 했는지 이다.
     

    LinkedList<String> list = new LinkedList<>();
    list.add("두쫀쿠");
    list.get(0);

     
    이렇게 구현해도 동작상의 문제는 없지만
    아마도 ..
    자바에서 리스트라는 자료구조를 설계한 "Josh Bloch, Neal Gafter" 은 리스트를 선언하는데
    구현방식이 영향을 주게하고 싶지 않았을 것이다.
     
    그래서 List를 인터페이스로 선언했다.
     
    인스턴스를 인터페이스로 선언하면 아래 예시처럼 구현체를 교체하는 것이 용이하다.
     

    // 가능
    List<String> list = new LinkedList<>();
    list.add("두쫀쿠");
    list.get(0);
    
    // 가능
    List<String> list = new ArrayList<>();
    list.add("두쫀쿠");
    list.get(0);

     
    그러나 구현체 자체로 인스턴스를 선언한다면 구현체 변경은 불가능하다.
     

    // 가능
    LinkedList<String> list = new LinkedList<>();
    list.add("두쫀쿠");
    list.get(0);
    
    // 불가능 !!
    LinkedList<String> list = new ArrayList<>();
    list.add("두쫀쿠");
    list.get(0);

     
    이것이 바로 직전글에서 소개했던 전략패턴이다. 
    https://moon-kotlin.tistory.com/108

    스프링 DI 기반 전략 패턴 : 레지스트리 패턴(Registry Pattern)

    들어가며입사하고 처음으로 도메인을 처음부터 설계해서 구성하고 구현하는 일을 맡게되었다!! 맡게된 도메인은 사실 간단한데, 사용자의 파일 다운로드 요청을 처리하고, 요청 자체를 기록하

    moon-kotlin.tistory.com

     
    전략패턴을 잘만 구현하면 저 글에서처럼 구현체를 용이하게 바꾸는 것도 가능하다.
     
     
     
     
    지금까지 인터페이스에대해 알아보았다.
    회사에서 전략패턴을 구현해보고
    이번 스프링 업데이트를 겪으면서 추상화의 강력함을 다시한번 느끼게되어서 이글을 작성하게 되었다. 
    이 글의 영감 90%는 요기요 기술블로그인 "치즈 돈카츠에 담긴 Interface의 개념" 에서 받았다.
     
     
    하하..

     
     
     
     

    마무리

    요즘은 새해를 맞이해서 바쁜 나날을 보내고있다.
    특히 QA기간에 쏟아지는 버그관련 지라티켓이라는 신세계를 맛보고있다. 

     

     
     
     
     
     

    참고 : https://techblog.yogiyo.co.kr/class-%EC%99%80-interface%EC%9D%98-%EC%B0%A8%EC%9D%B4-197444f8407f



     

Designed by Tistory.