공부/Java

자바 객체 지향 프로그래밍

Stair 2024. 8. 30. 13:04
반응형

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

 

절차 지향 프로그래밍

1. 이름 그대로 절차를 지향한다 실행 순서를 중요하게 생각하는 방식이다.

2. 절차 지향 프로그래밍은 프로그램의 흐름을 순차적으로 따르며 처리하는 방식이다. 즉, "어떻게"를 중심으로 프로그래밍 한다.

 

객체 지향 프로그래밍

1. 객체를 지향한다, 객체를 중요하게 생각한다.

2. 실제 세계의 사물이나 사건을 객체로 보고, 이러한 객체들 간의 상호작용을 중심으로 프로그래밍하는 방식이다. 즉, "무엇을"중심으로 프로그래밍 한다.

 

 

절차 지향은 데이터와 해당 데이터에 대한 처리 방식이 분리되어 있다. 반면 객체 지향에서는 데이터와 그 데이터에 대한 행동(메서드)이 하나의 '객체'안에 함께 포함되어 있다.

 

public static void main(String[] args) {
    int volume = 0;
    boolean isOn = false;

    isOn = true;
    System.out.println("음악 플레이어를 시작합니다.");

    //볼륨 증가, 감소
    volume++;
    System.out.println("volume = " + volume);
    volume++;
    System.out.println("volume = " + volume);
    volume--;
    System.out.println("volume = " + volume);

    System.out.println("음악 플레이어 상태 확인");
    if(isOn){
        System.out.println("음악플레이어가 켜져있다");
        System.out.println("volume = " + volume);
    }else {
        System.out.println("꺼져있어요`");
    }

}

 

지역변수로 on off와 볼륨 조절을 했던 코드를 클래스를 사용하도록 로직을 변경하였다.

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

 

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


    musicPlayerData.isOn = true;
    System.out.println("음악 플레이어를 시작합니다.");

    //볼륨 증가, 감소
    musicPlayerData.volume++;
    System.out.println("volume = " + musicPlayerData.volume);
    musicPlayerData.volume++;
    System.out.println("volume = " + musicPlayerData.volume);
    musicPlayerData.volume--;
    System.out.println("volume = " + musicPlayerData.volume);

    System.out.println("음악 플레이어 상태 확인");
    if(musicPlayerData.isOn){
        System.out.println("음악플레이어가 켜져있다");
        System.out.println("volume = " + musicPlayerData.volume);
    }else {
        System.out.println("꺼져있어요`");
    }


}

 

음악 플레이어와 관련된 데이터는 MusicPlayerData 클래스에 존재한다. 이후에 프로그램 로직이 더 복잡해져서 다양한 변수들이 추가 되더라도 음악 플레이어와 관련된 변수들은 MusicPlayerData data객체에 속해있으므로 쉽게 구분할 수 있다.

 

위와 같은 코드를 메소드를 사용하여 더 깔끔하게 작성할 수 있다.

 

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


    on(musicPlayerData);

    //볼륨 증가, 감소
    up(musicPlayerData);
    up(musicPlayerData);
    down(musicPlayerData);


    showStatus(musicPlayerData);

    off(musicPlayerData);


}

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

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

static void up(MusicPlayerData data){
    data.volume++;
    System.out.println("volume = " + data.volume);
}

static void down(MusicPlayerData data){
    data.volume--;
    System.out.println("volume = " + data.volume);
}

static void showStatus(MusicPlayerData data){
    System.out.println("음악 플레이어 상태 확인");
    if(data.isOn){
        System.out.println("음악플레이어가 켜져있다");
        System.out.println("volume = " + data.volume);
    }else {
        System.out.println("꺼져있어요`");
    }
}

 

 

하지만 이렇게 작성된 코드는 잘 짜여진 절차지향 코드일 뿐 객체지향 코드가 아니다. 순서를 중요시 하며 만든 코드이기 때문이다.

지금처럼 이렇게 작성한 코드의 한계는 바로 데이터와 기능이 분리되어 있다는 점이다. 음악 플레이어의 데이터는 MusicPlayerdata(클래스)에 있는데, 그 데이터를 사용하는 기능은 MusicPlayerMain에 있는 각각의 메서드에 분리되어 있다. 그래서 음악 플레이어와 관련된 데이터는 MusicPlayerData를 사용해야하고 음악 플레이어와 관련된 기능은 MusicPlayerMain의 메서드를 사용해야한다.

 

이렇게 데이터와 기능이 분리되어 있으면 관리해야할 포인트가 두곳으로 늘어나게 된다.

 

이러한 문제를 해결하기 위해 클래스에 메서드를 포함한다.

클래스는 데이터인 멤버 변수 뿐 아니라 기능 역할을 하는 메서드도 포함할 수 있다.

 

자바와 같은 객체지향 언어는 클래스 내부에 속성(데이터)과 기능(메서드)을 함께 포함할 수 있다. 클래스 내부에 멤버 변수 뿐만 아니라 메서드도 함께 포함할 수 있다는 뜻이다.

public class ValueData {
    int value;
    
    void add(){
        value++;
        System.out.println("숫자 증가 value = " + value);
    }
}

 

이 클래스에는 데이터인 value와 해당 데이터를 사용하는 기능인 add() 메서드를 함께 정의했다.

 

참고: 원칙적으로 메서드는 객체를 생성해야 호출할 수 있다 그런데 static이 붙으면 객체를 생성하지 않고도 메서드를 호출할 수 있다.

public static void main(String[] args) {
    ValueData valueData = new ValueData();

    valueData.add();
    valueData.add();
    valueData.add();
    
    System.out.println("최종 숫자 = " + valueData.value);

}

(x002)로 가정한다.

valueData.add()

add() 메서드를 호출하면 메서드 내부에서 value++를 호출하게 된다 .이때 value에 접근해야 하는데, 기본으로 본인 인스턴스에 있는 멤버 변수에 접근한다. 본인 인스턴스가 x002 참조값을 사용하므로 자기 자신인 x002.value에 접근하게 된다.

 

 

클래스는 속성(데이터, 멤버 변수)과 기능(메서드)을 정의할 수 있다.

객체는 자신의 메서드를 통해 자신의 멤버 변수에 접근할 수 있다.

-객체의 메서드 내부에서 접근하는 멤버 변수는 객체 자신의 멤버 변수이다.

 

 

기존에 만들었던 음악 플레이어를 객체 지향적으로 설계해보자.

 

public class MusicPlayer {
    int volume;
    boolean isOn;

    void on(){
        isOn= true;
        System.out.println("음악 플레이어를 실행합니다.");
    }
    void off(){
        isOn = false;
        System.out.println("음악 플레이어를 끕니다.");
    }
    void volumeUp(){
        volume++;
        System.out.println("볼륨을 1 증가시킵니다 volume: " + volume);
    }

    void volumeDown(){
        volume--;
        System.out.println("볼륨을 1 감소시킵니다 volume: " + volume);
    }
    void showStatus(){
        if (isOn == true){
            System.out.println("전원이 켜져있습니다.");
        }
        else {
            System.out.println("전원이 꺼져있습니다.");
        }
    }
}

 

 

public static void main(String[] args) {
    MusicPlayer musicPlayer = new MusicPlayer();

    musicPlayer.on();

    musicPlayer.volumeUp();
    musicPlayer.volumeUp();
    musicPlayer.volumeDown();

    musicPlayer.off();

    musicPlayer.showStatus();


}

 

 

마치 음악 플레이어를 만들고 그 기능만 호출하여 사용하는 객체 지향적인 코드가 완성되었다.

 

MusicPlayer를 사용하는 입장에서는 데이터인 volume, isOn과 같은 데이터는 전혀 사용하지 않는다. 또한 내부에 어떤 속성이 있는지 전혀 몰라도 된다. 제공하는 기능 중 필요한 기능을 호출해서 사용하기만 하면 된다.

 

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

 

코드가 더 읽기 쉬운 것은 물론이고, 속성과 기능이 한 곳에 있기 때문에 변경도 더 쉬워진다.

public class Rectangle {
    int width;
    int height;

    int calculateArea(){
        return width * height;
    }

    int calculatePerimeter(){
        return 2*(width + height);
    }

    boolean isSquare(){
        return width == height;
    }
}

 

public static void main(String[] args) {
    Rectangle rectangle = new Rectangle();

    rectangle.width = 8;
    rectangle.height = 5;


    int area = rectangle.calculateArea();
    System.out.println("area = " + area);
    int perimeter = rectangle.calculatePerimeter();
    System.out.println("perimeter = " + perimeter);
    boolean square = rectangle.isSquare();
    System.out.println("square = " + square);

}

 

 

 

 

public class Account {
    int balance;

    void deposit(int amount){
        balance += amount;
    }
    void withdraw(int amount){
        if(balance < amount){
            System.out.println("잔액이 부족합니다");
        }
        else {
            balance -= amount;
        }
    }
}

 

 

public static void main(String[] args) {
    Account account = new Account();

    account.deposit(10000);
    account.withdraw(9000);
    account.withdraw(2000);

    System.out.println("잔고 = " + account.balance);
}

 

 

 

 

정리

객체지향과 절차지향은 서로 대치되는 개념이 아니다.

다만 어디에 초점을 맞추는가에 둘의 차이가 있다. 객체지향의 경우 객체의 설계와 관계를 중시하고, 절차지향의 경우 데이터와 기능이 분리되어있고, 프로그램이 어떻게 작동하는지 그 순서에 초점을 맞춘다.

 

 

반응형

'공부 > Java' 카테고리의 다른 글

자바 패키지  (0) 2024.08.31
자바 생성자  (1) 2024.08.30
자바 기본형과 참조형  (0) 2024.08.29
자바 클래스와 데이터  (1) 2024.08.29
자바 객체 지향 프로그래밍과 절차 지향 프로그래밍  (0) 2024.08.29