김영한의 실전 자바 - 기본편 강의 | 김영한 - 인프런
김영한 | 실무에 필요한 자바 객체 지향의 핵심 개념을 예제 코드를 통해 쉽게 학습합니다., 국내 개발 분야 누적 수강생 1위, 제대로 만든 김영한의 실전 자바[사진][임베딩 영상]단순히 자바 문
www.inflearn.com
프로그래밍 방식은 크게 절차 지향 프로그래밍과 객체 지향 프로그래밍으로 나눌 수 있다.
절차 지향 프로그래밍
- 이름 그대로 절차를 지향한다. 쉽게 이야기해서 실행 순서를 중요하게 생각하는 방식이다.
- 프로그램의 흐름을 순차적으로 따르며 처리하는 방식이다. 즉, "어떻게"를 중심으로 프로그래밍한다.
객체 지향 프로그래밍
- 이름 그대로 객체를 지향한다. 쉽게 이야기해서 객체를 중요하게 생각하는 방식이다.
- 실제 세계의 사물이나 사건을 객체로 보고, 이러한 객체들 간의 상호작용을 중심으로 프로그래밍하는 방식이다. 즉, "무엇을" 중심으로 프로그래밍한다.
절차 지향은 데이터와 해당 데이터에 대한 처리 방식이 분리되어 있다. 반면 객체 지향에서는 데이터와 그 데이터에 대한 행동(메서드)이 하나의 '객체' 안에 함께 포함되어 있다.
절차 지향 프로그래밍
문제 : 음악 플레이어 만들기
요구 사항
- 음악 플레이어를 켜고 끌 수 있어야 한다.
- 음악 플레이어의 볼륨을 증가. 감소할 수 있어야 한다.
- 음악 플레이어의 상태를 확인할 수 있어야 한다.
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("음악 플레이어를 종료합니다.");
}
}
데이터 묶음
`MusicPlayerData`라는 클래스를 만들고, 음악 플레이어에 사용되는 데이터들을 여기에 묶어서 멤버 변수로 사용하자.
public class MusicPlayerData {
int volume = 0;
boolean isOn = false;
}
음악 플레이어에 사용되는 `volume`, `isOn` 속성을 `MusicPlayerData`의 멤버 변수에 포함했다.
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` 객체에 속해있으므로 쉽게 구분할 수 있다.
메서드 추출
코드를 보면 아래 각각의 기능들은 이후에 재사용될 가능성이 높다.
- 음악 플레이어 켜기, 끄기
- 볼륨 증가, 감소
- 음악 플레이어 상태 출력
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");
}
}
}
각각의 기능을 메서드로 만든 덕분에 각각의 기능이 모듈화되었다. 덕분에 다음과 같은 장점이 생겼다.
- 중복 제거: 로직 중복이 제거되었다. 같은 로직이 필요하면 해당 메서드를 여러 번 호출하면 된다.
- 변경 영향 범위: 기능을 수정할 때 해당 메서드 내부만 변경하면 된다.
- 메서드 이름 추가: 메서드 이름을 통해 코드를 더 쉽게 이해할 수 있다.
절차 지향 프로그래밍의 한계
`MusicPlayerData3` 코드의 한계는 바로 데이터와 기능이 분리되어 있다는 점이다. 음악 플레이어의 데이터는 `MusicPlayerData`에 있는데, 그 데이터를 사용하는 기능은 `MusicPlayerMain3`에 있는 각각의 메서드에 분리되어 있다. 그래서 음악 플레이어와 관련된 데이터는 `MusicPlayerData`를 사용해야 하고, 음악 플레이어와 관련된 기능은 `MusicPlayerMain3`의 각 메서드를 사용해야 한다.
각각의 메서드를 보면 대부분 `MusicPlayerData`의 데이터를 사용한다. 따라서 이후에 관련 데이터가 변경되면 `MusicPlayerMain3`부분의 메서드들도 변경해야 한다. 그리고 이렇게 데이터와 기능이 분리되어 있으면 유지보수 관점에서도 관리 포인트가 2곳으로 늘어난다.
하지만 객체 지향 프로그래밍이 나오면서 데이터와 기능을 온전히 하나로 묶어서 사용할 수 있게 되었다.
클래스와 메서드
클래스는 데이터인 멤버 변수 뿐 아니라 기능 역할을 하는 메서드도 포함할 수 있다.
public class ValueData {
int value;
void add() {
value++;
System.out.println("숫자 증가 value=" + value);
}
}
public class ValueObjectMain {
public static void main(String[] args) {
ValueData valueData = new ValueData();
valueData.add();
valueData.add();
valueData.add();
System.out.println("최종 숫자=" + valueData.value);
}
}
인스턴스 생성
ValueData valueData = new ValueData();
`valueData`라는 객체를 생성했다. 이 객체는 멤버 변수 뿐만 아니라 내부에 기능을 수행하는 `add()` 메서드도 함께 존재한다.
인스턴스의 메서드 호출
인스턴스의 메서드를 호출하는 방법은 멤버 변수를 사용하는 방법과 동일하다. `.`(dot)을 찍어서 객체 접근한 다음에 원하는 메서드를 호출하면 된다.
정리
- 클래스는 속성(데이터, 멤버 변수)과 기능(메서드)을 정의할 수 있다.
- 객체는 자신의 메서드를 통해 자신의 멤버 변수에 접근할 수 있다.
- 객체의 메서드 내부에서 접근하는 멤버 변수는 객체 자신의 멤버 변수이다.
객체 지향 프로그래밍
음악 플레이어라는 객체를 지향해보기 위해서는 프로그램의 실행 순서보다는 음악 플레이어 클래스를 만드는 것 자체에 집중해야 한다. 음악 플레이어가 어떤 속성(데이터)을 가지고 어떤 기능(메서드)을 제공하는지 이 부분에 초점을 맞추어야 한다.
음악 플레이어
- 속성: `volume`, `isOn`
- 기능: `on()`, `off()`, `volumeUp()`, `volumeDown()`, `showStatus()`
객체 지향 음악 플레이어
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");
}
}
}
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();
}
}
`MusicPlayer` 객체를 생성하고 필요한 기능(메서드)을 호출하기만 하면 된다. 필요한 모든 것은 `MusicPlayer` 안에 들어있다.
- `MusicPlayer`을 사용하는 입장에서는 `MusicPlayer`의 데이터인 `volume`, `isOn` 같은 데이터는 전혀 사용하지 않는다.
- `MusicPlayer`를 사용하는 입장에서는 이제 `MusicPlayer` 내부에 어떤 속성(데이터)이 있는지 전혀 몰라도 된다. `MusicPlayer`를 사용하는 입장에서는 단순하게 `MusicPlayer`가 제공하는 기능 중에 필요한 기능을 호출해서 사용하기만 하면 된다.
캡슐화
`MusicPlayer`를 보면 음악 플레이어를 구성하기 위한 속성과 기능이 마치 하나의 캡슐에 쌓여있는 것 같다. 이렇게 속성과 기능을 하나로 묶어서 필요한 기능을 메서드를 통해 외부에 제공하는 것을 캡슐화라 한다.
객체 지향 프로그래밍 덕분에 음악 플레이어 객체를 사용하는 입장에서는 진짜 음악 플레이어를 만들고 사용하는 것처럼 느껴진다. 그래서 코드가 더 읽기 쉬운 것은 물론이고, 속성과 기능이 한 곳에 있기 때문에 변경도 더 쉬워진다.
'Java' 카테고리의 다른 글
[Java/김영한] 패키지 (1) | 2024.09.08 |
---|---|
[Java/김영한] 생성자 (1) | 2024.09.08 |
[Java/김영한] 기본형과 참조형 (1) | 2024.09.07 |
[Java/김영한] 클래스와 데이터 (0) | 2024.09.06 |
[Java/김영한] 메서드 (0) | 2024.08.15 |