응애개발자
article thumbnail
728x90

1. 절차 지향 프로그래밍

프로그래밍 방식은 크게 절차 지향 프로그래밍과 객체 지향 프로그래밍으로 나눌 수 있습니다.

 

 

절차 지향 프로그래밍

  • 절차 지향 프로그래밍은 이름 그대로 절차를 지향합니다. 쉽게 이야기해서 실행 순서를 중요하게 생각하는 방식입니다.
  • 절차 지향 프로그래밍은 프로그램의 흐름을 순차적으로 따르며 처리하는 방식입니다. 즉, "어떻게"를 중심으로 프로그래밍합니다.

객체 지향 프로그래밍

  • 객체 지향 프로그래밍은 이름 그대로 객체를 지향합니다. 쉽게 이야기해서 객체를 중요하게 생각하는 방식입니다.
  • 객체 지향 프로그래밍은 실제 세계의 사물이나 사건을 객체로 보고, 이러한 객체들 간의 상호작용을 중심으로 프로그래밍하는 방식입니다. 즉, "무엇을" 중심으로 프로그래밍합니다.

절차 지향은 데이터와 해당 데이터에 대한 처리 방식이 분리되어 있습니다. 반면 객체 지향에서는 데이터와 그 데이터에 대한 행동(메서드)이 하나의 '객체' 안에 함께 포함되어 있습니다. 이 글만 보면 이해가 안 될 수 있습니다. 따라서 밑의 코드로 절차 지향에서 객체 지향으로 점진적으로 코드를 변경해 보겠습니다.

 

1-1. 절차 지향 음악 플레이어 만들기

package class1;

public class MusicPlayerMain1 {
    public static void main(String[] args) {
    
        int volume = 0;
        boolean isOn = false;
        
        //음악 플레이어 켜기
        isOn = true;
        System.out.println("음악 플레이어를 시작합니다");
        
        //볼륨 증가
        volume++;
        System.out.println("음악 플레이어 볼륨:" + volume);
        
        //볼륨 증가
        volume++;
        System.out.println("음악 플레이어 볼륨:" + volume);
        
        //볼륨 감소
        volume--;
        System.out.println("음악 플레이어 볼륨:" + volume);
        
        //음악 플레이어 상태
        System.out.println("음악 플레이어 상태 확인");
        if (isOn) {
            System.out.println("음악 플레이어 ON, 볼륨:" + volume);
        } else {
            System.out.println("음악 플레이어 OFF");
        }
        
        //음악 플레이어 끄기
        isOn = false;
        System.out.println("음악 플레이어를 종료합니다");
    }
}

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

 

위 코드를 점진적으로 변경해 보겠습니다.

 

전체 코드 ex) 데이터 묶음

package class1;

public class MusicPlayerData {
    int volume = 0;
    boolean isOn = false;
}
package class1;

/**
 * 음악 플레이어와 관련된 데이터 묶기
 */

public class MusicPlayerMain2 {
    public static void main(String[] args) {
        MusicPlayerData data = new MusicPlayerData();
        
        //음악 플레이어 켜기
        data.isOn = true;
        System.out.println("음악 플레이어를 시작합니다");
        
        //볼륨 증가
        data.volume++;
        System.out.println("음악 플레이어 볼륨:" + data.volume);
        
        //볼륨 증가
        data.volume++;
        System.out.println("음악 플레이어 볼륨:" + data.volume);
        
        //볼륨 감소
        data.volume--;
        System.out.println("음악 플레이어 볼륨:" + data.volume);
        
        //음악 플레이어 상태
        System.out.println("음악 플레이어 상태 확인");
        if (data.isOn) {
            System.out.println("음악 플레이어 ON, 볼륨:" + data.volume);
        } else {
            System.out.println("음악 플레이어 OFF");
        }
        
        //음악 플레이어 끄기
        data.isOn = false;
        System.out.println("음악 플레이어를 종료합니다");
    }
}

음악 플레이어와 관련된 데이터는 MusicPlayerData 클래스에 존재합니다. 이제 이 클래스를 사용하도록 기존 로직을 변경했습니다. 이후에 다양한 변수들이 추가되더라도 음악 플레이어와 관련된 변수들은 MusicPlayerData data 객체에 속해있으므로 쉽게 구분할 수 있습니다. 하지만 코드가 중복되는 부분들이 있으니 조금 더 수정해 보겠습니다.

 

전체 코드 ex) 메서드 추출

package class1;

/**
 * 메서드 추출
 */

public class MusicPlayerMain3 {
    public static void main(String[] args) {
        MusicPlayerData data = new MusicPlayerData();
        //음악 플레이어 켜기
        on(data);
        //볼륨 증가
        volumeUp(data);
        //볼륨 증가
        volumeUp(data);
        //볼륨 감소
        volumeDown(data);
        //음악 플레이어 상태
        showStatus(data);
        //음악 플레이어 끄기
        off(data);
    }
    static void on(MusicPlayerData data) {
        data.isOn = true;
        System.out.println("음악 플레이어를 시작합니다");
    }
    static void off(MusicPlayerData data) {
        data.isOn = false;
        System.out.println("음악 플레이어를 종료합니다");
    }
    static void volumeUp(MusicPlayerData data) {
        data.volume++;
        System.out.println("음악 플레이어 볼륨:" + data.volume);
    }
    static void volumeDown(MusicPlayerData data) {
        data.volume--;
        System.out.println("음악 플레이어 볼륨:" + data.volume);
    }
    static void showStatus(MusicPlayerData data) {
        System.out.println("음악 플레이어 상태 확인");
        if (data.isOn) {
            System.out.println("음악 플레이어 ON, 볼륨:" + data.volume);
        } else {
            System.out.println("음악 플레이어 OFF");
        }
    }
}

이렇게 기능을 메서드로 만들어서 모듈화 시켰습니다. 덕분에 다음과 같은 장점이 생겼습니다.

  • 중복 제거 : 로직 중복이 제거되었습니다. 같은 로직이 필요하면 해당 메서드를 여러 번 호출하면 됩니다.
  • 변경 영향 범위 : 기능을 수정할 때 해당 메서드 내부만 변경하면 됩니다.
  • 메서드 이름 추가 : 메서드 이름을 통해 코드를 더 쉽게 이해할 수 있습니다.
모듈화 : 쉽게 이야기해서 레고 블록을 생각하시면 됩니다. 여기서는 음악 플레이어의 기능이 필요하면 해당 기능을 메서드 호출 만으로 손쉽게 사용할 수 있습니다. 이제 음악 플레이어와 관련된 메서드를 조립해서 프로그램을 작성할 수 있습니다.

 

1-2. 절차 지향 프로그래밍의 한계

위에서 작성한 코드의 한계는 바로 데이터와 기능이 분리되어 있다는 점입니다. 음악 플레이어의 데이터는 MusicPlayerData에 있는데, 그 데이터를 사용하는 기능은 MusicPlayerMain3에 있는 각각의 메서드에 분리되어 있습니다. 그래서 음악 플레이어와 관련된 데이터는 MusicPlayerData를 사용해야 하고, 음악 플레이어와 관련된 기능은 MusicPlayerMain3의 각 메서드를 사용해야 합니다.

 

하지만 여기서 데이터와 그 데이터를 사용하는 기능은 매우 밀접하게 연관되어 있습니다. 각각의 메서드를 보면 대부분 MusicPlayerData의 데이터를 사용합니다. 따라서 이후 관련 데이터가 변경되면 MusicPlaayerMain3 부분의 메서드들도 함께 변경해줘야 합니다. 이렇게 데이터와 기능이 분리되어 있으면 유지보수 관점에서도 관리 포인트가 2곳으로 늘어나게 됩니다

 

객체 지향 프로그래밍이 나오기 전까지는 이처럼 데이터와 기능이 분리되어 있었습니다. 그렇다면 데이터와 기능을 온전히 묶어서 사용해 보겠습니다.

 

2. 객체 지향 프로그래밍

이제는 음악 플레이어라는 개념을 객체로 온전히 만드는 것이 더 중요합니다. 그러기 위해서는 프로그램의 실행 순서보다는 음악 플레이어 클래스를 만드는 것 자체에 집중해야 합니다. 음악 플레이어가 어떤 속성(데이터)을 가지고 어떤 기능(메서드)을 제공하는지 초점을 맞추어야 합니다. 

 

2-1. 객체 지향 음악 플레이어 만들기

package class1;

public class MusicPlayer {

    int volume = 0;
    boolean isOn = false;
    
    void on() {
        isOn = true;
        System.out.println("음악 플레이어를 시작합니다");
    }
    
    void off() {
        isOn = false;
        System.out.println("음악 플레이어를 종료합니다");
    }
    
    void volumeUp() {
        volume++;
        System.out.println("음악 플레이어 볼륨:" + volume);
    }
    
    void volumeDown() {
        volume--;
        System.out.println("음악 플레이어 볼륨:" + volume);
    }
    
    void showStatus() {
        System.out.println("음악 플레이어 상태 확인");
        if (isOn) {
            System.out.println("음악 플레이어 ON, 볼륨:" + volume);
        } else {
            System.out.println("음악 플레이어 OFF");
        }
    }
}

MusicPlayer 클래스에 음악 플레이어에 필요한 속성과 기능을 모두 정의했습니다. 이제 음악 플레이어가 필요한 곳에서 이 클래스만 있으면 온전한 음악 플레이어를 생성해서 사용할 수 있습니다. 음악 플레이어를 사용하는데 필요한 모든 속성과 기능이 하나의 클래스에 포함되어 있습니다.

 

package class1;

/**
 * 객체 지향
 */

public class MusicPlayerMain4 {
    public static void main(String[] args) {
    
        MusicPlayer player = new MusicPlayer();
        //음악 플레이어 켜기
        player.on();
        //볼륨 증가
        player.volumeUp();
        //볼륨 증가
        player.volumeUp();
        //볼륨 감소
        player.volumeDown();
        //음악 플레이어 상태
        player.showStatus();
        //음악 플레이어 끄기
        player.off();
    }
}

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

 

MusicPlayer 객체를 생성하고 필요한 기능(메서드)을 호출하기만 하면 됩니다. 필요한 것은 MusicPlayer 안에 들어있습니다.

  • MusicPlayer를 사용하는 입장에서는 MusicPlayer의 데이터인 volume, isOn 같은 데이터는 전혀 사용하지 않습니다.
  • MusicPlayer를 사용하는 입장에서는 이제 MusicPlayer 내부에 어떤 속성(데이터)이 있는지 전혀 몰라도 됩니다. MusicPlayer를 사용하는 입장에서는 단순하게 MusicPlayer가 제공하는 기능 중에 필요한 기능을 호출해서 사용하기만 하면 됩니다.

2-2. 캡슐화

MusicPlayer를 보면 음악 플레이어를 구성하기 위한 속성과 기능이 마치 하나의 캡슐에 쌓여있는 것처럼 보입니다. 이렇게 속성과 기능을 하나로 묶어서 필요한 기능을 메서드를 통해 외부에 제공하는 것을 캡슐화라 합니다.

 

'Language > Java' 카테고리의 다른 글

[Java] 패키지  (2) 2023.12.18
[Java] 생성자  (0) 2023.12.18
[Java] 변수와 초기화  (0) 2023.12.17
[Java] 인자, 매개변수  (1) 2023.12.14
[Java] 기본형과 참조형  (2) 2023.12.13
profile

응애개발자

@Eungae-D

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!