절차 지향 프로그래밍과 객체 지향 프로그래밍
- 절차 지향 프로그래밍 - 이름 그대로 절차를 지향하며 실행 순서를 중요하게 생각하는 방식이다.
프로그램의 흐름을 순차적으로 따르며 처리하고 "어떻게"를 중심으로 프로그래밍한다. - 객체 지향 프로그래밍 - 객체지를 지향하며 실제 세게의 사물이나 사건을 객체로 보고, 이러한 객첼들 간의 상호작용을 중심으로
프로그래밍하는 방식이다. "무엇을" 중식으로 프로그래밍 한다.
차이점 - 절차 지향은 해당 데이터에 대한 처리 방식이 분리되어있고, 객체 지향은 데이터와 그 데이터에 대한 행동이 하나의 '객체'안에 함께 포함되어 있다.
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);
//음악 플레이어 상태
System.out.println("음악 플레이어 상태" + isOn);
//음악 플레이어 끄기
isOn = false;
System.out.println("음악 플레이어 끄기" + isOn);
}
}
위 코드는 순서에 맞게 작성된 절차 지향 프로그래밍이다.
public class MusicPlayerMain1 {
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);
//음악 플레이어 상태
System.out.println("음악 플레이어 상태" + data.isOn);
//음악 플레이어 끄기
data.isOn = false;
System.out.println("음악 플레이어 끄기" + data.isOn);
}
}
위 코드는 기존 코드에 클래스를 추가하여 기존로직을 변경했다.
이후에 프로그램 로직이 더 복잡해져서 다양한 변수들이 추가되더라도 음악 플레이어와 관련된 변수들은 MusicPlayerData data 객체에 속해있으므로 더 쉽게 구별할 수 있다.
public class MusicPlayerMain1 {
public static void main(String[] args) {
MusicPlayerData data = new MusicPlayerData();
//음악 플레이어 켜기
on(data);
//볼륨증가
volume(data);
//볼륨감소
volume2(data);
//음악 플레이어 상태
System.out.println("음악 플레이어 상태" + data.isOn);
//음악 플레이어 끄기
off(data);
}
static void on(MusicPlayerData data){
data.isOn = true;
System.out.println("음악 플레이어를 시작합니다." + data.isOn);
}
static void off(MusicPlayerData data){
data.isOn = false;
System.out.println("음악 플레이어를 종료합니다." + data.isOn);
}
static void volume(MusicPlayerData data){
data.volume++;
System.out.println("음악 플레이어 볼륨 업" + data.volume);
}
static void volume2(MusicPlayerData data){
data.volume--;
System.out.println("음악 플레이어 볼륨 다운" + data.volume);
}
}
위 코드는 각각의 기능을 메서드로 만들어 기능을 모듈화 시켰다.
모듈화: 쉽게 레고 블럭으로 비유할 수 있다.
필요한 블럭을 가져다 꼽아서 사용하는 개념으로 위 코드에서는 음악플레이어의 기능이 필요하면 해당 기능을 메서드 호출만으로 쉽게 사용이 가능하다.
모듈화의 장점은 크게 세가지가 있다.
- 중복 제거: 로직 중복이 제거되어 같은 로직이 필요하면 해당 메서드를 여러분 호출하면 된다.
- 변경 영향 범위: 기능을 수정할 때 해당 메서드 내부만 변경하면 된다.
- 메서드 이름 추가: 메서드 이름을 통해 코드를 더 쉽게 이해할 수 있다.
지금까지 위에 만들어진 코드들은 절차 지향 프로그래밍이다.
하지만 절차 지향 프로그래밍에는 한계가 있다.
음악 플레이어의 데이터는 MusicPlayerData의 데이터를 사용한다. 따라서 이후에 관련 데이터가 변경되면 MusicPlayerMain 부분의 메서드들도 함께 변경해야 한다. 그리고 이렇게 데이터와 기능이 분리되어 있으면 유지보수 관점에서도 관리 포인트가 2곳으로 늘어난다.
객체 지향 프로그래밍이 나오기 전까지는 지금과 같이 데이터와 기능이 분리되어 있엇다.
따라서 지금과 같은 코드가 최선이었지만 객체지향 프로그랭이 나오면서 데이터와 기능을 온전히 하나로 묶어서 사용할 수 있게 되었다.
아래에 데이터와 기능을 하나로 묶는다는게 어떤 의미인지 예제를 살펴보자.
public class MusicPlayer {
int volume = 0;
boolean isOn = false;
void on(){
isOn = true;
System.out.println("음악 플레이어를 시작합니다." + isOn);
}
void off(){
isOn = false;
System.out.println("음악 플레이어를 종료합니다." + isOn);
}
void volumeUp(){
volume++;
System.out.println("음악 플레이어 볼륨 업" + volume);
}
void volumeDown(){
volume--;
System.out.println("음악 플레이어 볼륨 다운" + volume);
}
}
public class MusicPlaterMain4 {
public static void main(String[] args) {
MusicPlayer mp = new MusicPlayer();
//음악플레이어 켜기
mp.on();
//볼륨 증가
mp.volumeUp();
//볼륨 감소
mp.volumeDown();
//종료
mp.off();
}
}
위 코드는 클래스 안에 메소드를 구현했다.
MusicPlayer 객체를 생성하고 필요한 기능(메서드)을 호출하기만 하면 된다.
필요한 모든 기능을 MusicPlayer 안에 넣은 것이다.
- MusicPlayer를 사용하는 입장에서는 MusicPlayer의 데이터인 volume, isOn과 같은 데이터는 전혀 사용하지 않는다.
- MusicPlyer를 사용하는 입장에서는 이제 MusicPlayer 내부에 어떤 속성(데이터)이 있는지 전혀 몰라도 되며, 제공하는 기능 중에 필요한 기능을 단순히 호출해서 사용하기만 하면 된다.
캡슐화 - MusicPlayer를 보면 속성과 기능을 하나로 묶어서 필요한 기능을 메서드를 통해 외부에 제공하는 것을 캡슐화라고 한다.
장점
객체 지향 프로그래밍 덕분에 코드의 파악이 더 쉽고 변경이 쉬워진다.
예를들어 MusicPlayer 내부 코드가 변하는 경우에 다른 코드를 변경하지 않아도 되고, 멤버 변수인 volume라는 필드 이름이 변경된다 하더라도 MusicPlayer 내부에서만 변경하면 된다.
물론 MusicPlayer에서 호출하는 메서드 이름을 변경한다면 MusicPlayer를 사용하는 곳에서 코드를 변경해야 한다.
단순하게 설명하자면 객체 지향형 프로그래밍이란 클래스가 캡슐화 된다는 것이다.