본문 바로가기

기타/객체지향 토막글

오버로딩과 오버라이딩 - 수필 객체지향

오버로딩은 마치 맥가이버칼의 부속품과 같다. 같은 몸통(메소드 이름)에서 꺼내는 위치만 바꾸면(인자값) 다양한 기능이 발견된다. 오버로딩은 같은 이름의 메소드의 인자값(=시그네처)를 다르게 주어 개별적으로 개발자 입맛에 맞게 호출할 수 있는 방법이다.

내 경험으로 오버로딩은 생성자 호출에서 특히 많이 쓰인다. 처음 객체를 생성할때 오버로딩된 다양한 생성자들의 용도를 파악하여, 써야 되는 상황에 알맞게 해당 객체를 사용할 수 있다.

- 생성자 오버로딩 예제-병아리 부화 클래스
public static void main( String[] args ) throws Exception {
    …..
    Chick chick1 = new Chick(); // 1
    Chick chick2 = new Chick(“먹이”); // 2
    Chick chick3 = new Chick(“먹이", "물"); // 3
    …...
}

- 생성자 오버로딩 예제-병아리 예제 클래스
public class Chick {
    public Chick() {
        System.out.println("배가 고파요");
    }

    pulbic Chick(String food) {
        System.out.println(food+" 맛 있어요. 근데 목이 말라요");
    }

    pulbic Chick(String food, String water) {
        System.out.println(food+" 먹고 "+water+" 도 먹고");
    }
}

오버라이딩은 마치 진화하는 자동차 모델의 특징 변화와 같다. 예를 들어 유명한 자동차 소나타 시리즈는 소나타1에서 EF소나타, New EF소나타, NF 소나타, 그리고 현재 YF소나타로 진화하고 있다.

소나타 시리즈가 진화될 때마다(상속받을때는) 먼저 자동차 모델명이 조금씩 바뀐다.(자동차 모델명을 정하는 메소드가 오버라이드 된다.) 그외 자동차의 여러 성능이라던지 가격이라던지 자동차의 모든 특징과 기능들이 그대로인 것은 그대로 상속받고 바뀌는 것은 자식 클래스에서 다시 구현한다.

오버라이딩은 부모 객체에서 정의한 메소드를 해당 자식 객체의 입맛에 맞게 재구현하는 개념이다.

 

[그림 1.1.7-1, 소나타 객체 상속 구성도, 소나타1에 기본적으로 부가 서비스 시스템을 정의하는 serviceSystem 메소드가 존재한다. 소나타1에서는 일반 소파, 구식 라디오 등이 구비되어 있다. 소나타1을 이어받은(상속받은) EF소나타는 serviceSystem 메소드를 오버라이드 했다. 인체공학적 소파, CD플레이어등의 발전된 기능을 재정의 하였다. NF소나타도 역시 상위 클래스의 serviceSystem을 재 정의 하면서 더 발전된 기능을 제공하고 있다.]

오버라이딩 개념은 객체지향에서 중요하다. 객체지향의 장점을 누릴 수 있는 상속과 폴리모피즘, 인터페이스와 구상 클래스, 더 나아가 디자인패턴에서도 오버라이드를 통해 프로그램을 유연하고 확장성 높게 다룰 수 있다.

상속과 폴리모피즘(다형성) 개념, 부모 클래스를 상속받은 클래스들은 대부분 부모 클래스의 주기능을 오버라이드 하고 있다. ‘부모 클래스’와 ‘상속받은 클래스’를 묶어서 ‘객체 패밀리’라고 하고, ‘객체 패밀리’를 사용하는 다른 객체를 ‘클라이언트 객체’라고 이름지어 보겠다. 제대로 된 객체지향 기법을 사용한 객체 구성이라면 ‘클라이언트 객체’는 ‘객체 패밀리’의 ‘부모 클래스’에만 의존하고 있을 것이다. 이때 ‘클라이언트 객체’를 제어하는 ‘실행 클래스’ 가 ‘클라이언트 객체’에게 ‘객체 패밀리’의 ‘상속받은 클래스’ 중에 하나를 선택하여 인자값으로 넘겨준다. 이렇게 하면 유연하고 확장성 높은 전형적인 객체지향의 장점을 누릴 수 있는데, 이 상속과 폴리모피즘의 구현에 오버라이딩 개념이 중요하게 작용한다.

 

[그림 1.1.7-2, 상속과 폴리모피즘 개념도]

인터페이스와 구상 클래스, 인터페이스와 인터페이스를 구현하는 구상 클래스로 나눌때의 이로움은 상속과 폴리모피즘과 비슷하고 그 안에 장점이 포함되어 있다. ‘인터페이스를 쓰는 클래스’를 ‘클라이언트 클래스’라고 정의해 보겠다. ‘클라이언트 클래스’ 는 인터페이스에서 명시한 기능만 알고 그 구현 클래스(=구현 방법)은 전혀 모른다. ‘클라이언트 클래스’가 어떤 방식으로 인터페이스에 명시한 기능을 쓸 것인지는 ‘실행 클래스’가 결정한다. 덕분에 ‘클라이언트 클래스’는 오직 인터페이스 명시한 기능만 알고도 여러 구상 클래스를 교체 하거나 확장할 수 있어서 유연하고 확장성 높은 개발이 가능하다. 인터페이스를 구현한 구상 클래스는 기본적으로 인터페이스에 명시한 기능을 오버라이드 하기 때문에 인터페이스와 구상 클래스 에서도 오버라이딩 개념이 중요하게 작용한다.

 

디자인패턴의 가장 기본이 되는 객체 구성도는 상속과 폴리모피즘, 인터페이스와 구상 클래스 설명을 통해 그려지는 구성도와 같다. 이 객체 구성도를 바탕으로 파생된 다양한 패턴이 존재하는데 그 바탕에는 상속과 폴리모피즘, 인터페이스와 구상 클래스, 그리고 오버라이딩 개념 등을 중요하게 사용한다.

[삽화]

이렇게 오버라이드는 객체지향의 장점을 살려주기 위해 밑바닥에서 알게 모르게 중요하게 작동하는 개념이다.


덧) 아직 고쳐쓰기가 덜 되었습니다. 예를 들면 도입부는 그럴듯하게 쓰다가 실제 설명부분에서는 풀어쓰는 부분이 덜 되었습니다. 어려운 용어의 풀어쓰기가 안되었습니다. 기타 삽화가 부족함을 이해해 주시길 바라며, 향후 책에 쓰일 원천 자료이기 때문에 펌은 불허, 링크 환영 합니다. 조언 부탁드립니다. ^ ^;