Java 객체 지향 프로그래밍 기본

Java 의 객체 지향 프로그래밍을 배우기 전 절차 지향에 대해 알아보도록 한다.

절차 지향 프로그래밍

  • 절차를 지향한다. 실행 순서를 중요하게 생각한다.
  • 프로그램 흐름을 순차적으로 따라 처리하는 방식이다.
  • 전체 코드를 어떻게 구성할 지 프로그래밍 한다.

객체 지향 프로그래밍

  • 객체를 지향한다. 객체를 중점적으로 생각하는 방식이다.
  • 실제 세계의 사물이나 사건을 객체로 보고, 객체들 간의 상호작용 중심으로 프로그래밍 하는 방식, 무엇을 중점적으로 프로그래밍 한다.

두 개의 프로그래밍 차이점

  • 절차 지향은 데이터와 데이터 간 처리 방식이 분리되어 있다.
  • 객체 지향은 데이터와 그 데이터에 대한 행동(메소드)이 하나의 객체 안에 함께 포함되어 있다.

절차 지향부터 프로그래밍 해보고 객체 지향 프로그래밍으로 변경해보도록 한다.


문제, 음악 플레이어 만들기 - 절차

음악 플레이어를 만들어 보도록 한다.

요구사항:

  • 음악 플레이어를 끄고 킨다
  • 음악 플레이어의 볼륨 증가, 감소한다.
  • 음악 플레이어의 상태를 확인한다.

예시 출력:

음악 플레이어를 시작합니다.
음악 플레이어 볼륨:1
음악 플레이어 볼륨:2
음악 플레이어 볼륨:1
음악 플레이어 상태 확인
음악 플레이어 ON, 볼륨:1
음악 플레이어를 종료합니다.

풀이:

public class Main {
    public static void main(String[] args) {
        int volume = 0;
        boolean isOn = false;
        System.out.println("음악 플레이어를 시작합니다.");
        isOn = true;
        volume++;
        System.out.println("음악 플레이어 볼륨: " + volume);
        volume++;
        System.out.println("음악 플레이어 볼륨: " + volume);
        volume--;
        System.out.println("음악 플레이어 볼륨: " + volume);
        if (isOn) {
            System.out.println("음악 플레이어 ON, 볼륨: " + volume);
        } else {
            System.out.println("음악 플레이어 OFF");
        }

        volume = 0;
        isOn = false;
        System.out.println("음악 플레이어를 종료합니다.");
    }
}

절차대로 프로그래밍이 동작한다.


문제, 음악 플레이어 만들기 - 절차(클래스)

앞에서 작성한 코드를 수정하여 클래스를 도입한다. 음악 플레이어에 사용한 데이터를 클래스로 묶어 멤버변수로 활용한다.

음악 플레이어 - 데이터 묶음(클래스)

public static MusicPlayerData {
    int volume = 0;
    boolean isOn = false;
}

음악 플레이어에 사용한 volume, isOn 속성을 MusicPlayerData의 멤버 변수에 포함한다.

풀이

public class Main {
    public static class MusicPlayerData {
        int volume;
        boolean isOn = false;
    }

    public static void main(String[] args) {
        MusicPlayerData data = new MusicPlayerData();
        System.out.println("음악 플레이어를 시작합니다.");
        data.isOn = true;
        data.volume++;
        System.out.println("음악 플레이어 볼륨: " + volume);
        data.volume++;
        System.out.println("음악 플레이어 볼륨: " + volume);
        data.volume--;
        System.out.println("음악 플레이어 볼륨: " + volume);
        if (data.isOn) {
            System.out.println("음악 플레이어 ON, 볼륨: " + volume);
        } else {
            System.out.println("음악 플레이어 OFF");
        }

        data.volume = 0;
        data.isOn = false;
        System.out.println("음악 플레이어를 종료합니다.");
    }
}

문제, 음악 플레이어 만들기 - 절차(메소드)

코드에서 중복 코드를 개선한다.

중복 코드

data.volume++;
System.out.println("음악 플레이어 볼륨: " + data.volume);

data.volume++;
System.out.println("음악 플레이어 볼륨: " + data.volume);

volume 멤버변수 값을 증감시킬 뿐 아니라 메시지가 출력되어야 하는데, 보다시피 중복 코드를 사용하고 있다.

그외의 각각의 기능들은 코드가 커질수록 재사용 될 가능성이 있다.

중복 가능성이 큰 기능

  • 음악 플레이어 켜기, 끄기
  • 음악 플레이어 볼륨 증가, 감소
  • 음악 플레이어 상태 출력

위와 같은 기능을 메소드를 이용하여 구분한다.

public class Main {
    public static class MusicPlayerData {
        int volume;
        boolean isOn = false;
    }

    public static void main(String[] args) {
        MusicPlayerData data = new MusicPlayerData();

        on(data);
        volumeUp(data);
        volumeUp(data);
        volumeDown(data);
        showStatus(data);
        off(data);
    }

    public static void on(MusicPlayerData data) {
        data.isOn = true;
        System.out.println("음악 플레이어를 시작합니다.");
    }

    public static void volumeUp(MusicPlayerData data) {
        data.volume++;
        System.out.println("음악 플레이어 볼륨: " + data.volume);
    }

    public static void volumeDown(MusicPlayerData data) {
        data.volume--;
        System.out.println("음악 플레이어 볼륨: " + data.volume);
    }

    public static void off(MusicPlayerData data) {
        data.isOn = false;
        System.out.println("음악 플레이어를 종료합니다.");
    }

    public static void showStatus(MusicPlayerData data) {
        if (data.isOn) {
            System.out.println("음악 플레이어 ON, 볼륨: " + data.volume);
        } else {
            System.out.println("음악 플레이어 OFF");
        }
    }

}

각각의 기능을 메소드로 만들어 모듈화 되었다. 모듈화 장점은 다음과 같다.

  • 중복 제거: 로직 중복이 제거되어 필요한 경우 메소드 하나를 여러번 호출한다.
  • 변경 영향 범위: 기능 수정 시 해당 메소드 내부만 변경한다.
  • 메서드 이름: 메소드 이름을 통해 이 코드가 어떤 역할 및 행동을 하는지 쉽게 이해 할 수 있다.

절차 지향 프로그래밍 한계

코드에서 데이터를 묶고, 메소드를 이용한 모듈화도 성공적으로 완료하였다. 이로 인해 읽기 좋고, 유지보수 용이한 코드를 완성시킬 수 있다.

하지만 이 코드의 한계는 데이터와 기능이 분리되어 있음을 확인할 수 있다. 음악 플레이어 데이터는 MusicPlayerData 가 들어가는데, 이 데이터를 사용하는 기능은 Main 클래스의 각각의 메소드로 분리되어 개발되어 있다. 음악 플레이어 데이터는 MusicPlayerData를 사용해야 했고, 음악 플레이어와 관련된 기능은 Main 클래스의 메소드를 이용할 수밖에 없다.

데이터와 이 데이터를 사용하는 기능은 매우 밀접하게 연관되고, 각각의 메소드에서는 MusicPlayerData 멤버변수를 사용하였다. 데이터가 변경되면 Main 클래스의 메소드도 함께 변경해야하고 유지보수 관점에서도 두 곳으로 늘어난다.

앞 서 만든 코드는 절차 지향 프로그래밍으로서 최선이다. 이제 객체 지향 프로그래밍으로 데이터와 기능가 하나로 묶어 사용해보도록 한다.