일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 31 |
- 표준함수
- 다음 큰 숫자 풀이
- 코틀린
- java
- CLI
- 접근 제어자
- 인터프리터
- git push
- GitHub
- @SpringBootApplication
- Public
- 캡슐화
- springboot
- apply
- JIT
- 프로그래머스 #lv0
- git commit -m
- Git
- open ai key 발급
- 싱글톤
- Private
- 프로필 구현
- git add
- assertThat()
- JVM
- git clone
- @Configuration
- streamlit
- static
- git pull
- Today
- Total
우당탕탕 개발_𝒍𝒐𝒈
객체 지향 프로그래밍 본문
절차 지향 코드를 객체 지향 코드로 리펙토링 하며 객체 지향 프로그래밍에 대한 개념을 이해한다.
프로그래밍 방식
- 절차 지향 프로그래밍 (모듈화) <그림 추가>
- 객체 지향 프로그래밍 (캡슐화) <그림 추가>
절차 지향 프로그래밍 | . . . | 객체 지향 프로그래밍 |
"How"를 중심으로, 순차적으로 코드의 흐름에 따라 처리하는 프로그래밍 방식 | 방식 | 실제 세계의 사물, 사건을 의미하는 객체 간의 상호작용을 중심으로 둔 프로그래밍 방식 |
분리 | 차이점 (기준 : 데이터와 기능에 대한 처리 방식) |
'객체'안에 포함 |
Music Player 만들기
#1 요구사항
- 음악 플레이어를 켜고 끌 수 있어야 한다.
- 음악 플레이어의 볼륨을 증가, 감소 할 수 있어야 한다.
- 음악 플레이어의 상태를 확인 할 수 있어야 한다.
#2 절차지향 프로그래밍의 문제점
- 요구사항에 따라 절차지향적으로 아래와 같이 코드를 작성해 본 후 문제점을 탐색해 보았습니다.
//음악 플레이어의 볼륨, 상태 초기값 지정
int volume =0;
boolean isOn = true;
//음악플레이어 키기
OnAndOff = true;
System.out.println("플레이어를 실행시킵니다.");
//볼륨 증가
volume ++;
System.out.println("볼륨 증가:"+ volume);
//볼륨 증가
volume ++;
System.out.println("볼륨 증가:"+ volume);
//볼륨 감소
volume --;
System.out.println("볼륨 감소:"+ volume);
//상태 확인
if (isOn){
System.out.println("플레이어가 실행되고 있습니다.");
}else {
System.out.println("플레이어가 종료되었습니다.");
}
//종료
isOn = false;
System.out.println("플레이어를 종료합니다.");
- 플레이어의 속성과 기능이 명확하게 분리가 되어있지 않아 가독성이 떨어질 수 있습니다.
- 볼륨 증가 및 감소에 대한 기능의 코드가 중복되어 있습니다. 이는 코드의 유지/보수를 어렵게 합니다.
- 속성을 변경하는 부분이 여러 곳에 배치되어 있어 추적 및 디버깅에 어려움을 줄 수 있습니다.
#3 절차지향 ➡️객체지향
순서 : 데이터 묶기 >> 메서드 추출 >> 클래스 안에 메서드 넣기
1. 데이터 묶기
- MusicPlayerData 플레이어의 속성을 가진 클래스 생성
- main 메서드에 new 예약어를 사용하여 MusicPlayerData의 참조값을 가진 data 인스턴스 생성
-.(dot)을 통해 해당 데이터를 가져옴
public class MusicPalyerData {
//음악 플레이어 속성
int volume = 0;
boolean isOn = true;
}
public static void main(String[] args) {
MusicPalyerData data= new MusicPalyerData();
//음악 플레이어의 볼륨, 상태 초기값 지정
/* int volume =0;
boolean isOn = true;*/
//음악플레이어 키기
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);
//상태 확인
if ( data.isOn){
System.out.println("플레이어가 실행되고 있습니다.");
}else {
System.out.println("플레이어가 종료되었습니다.");
}
//종료
data.isOn = false;
System.out.println("음악 플레이어를 종료합니다.");
- 위 과정을 통해 조금이나마 데이터의 관리가 용이해졌습니다. 하지만 아직까지도 중복코드가 많이 보이기 때문에 메서드를 통해 제거해 보겠습니다.
2. 메서드 추출하기
⭐ 재사용될 가능성이 높은 기능을 메서드 속에 담아보자!
- 플레이어 on, off / volume up, down / 플레이어 상태 (showpalyer)
public static void main(String[] args) {
MusicPalyerData data= new MusicPalyerData();
//음악플레이어 켜기
on(data);
//볼륨 증가
volumeUp(data);
//볼륨 증가
volumeUp(data);
//볼륨 감소
volumeDown(data);
//종료
off(data);
//상태 확인
showPlayer(data);
}
static void on(MusicPalyerData data){
data.isOn = true;
System.out.println("플레이어를 실행시킵니다.");
}
static void off(MusicPalyerData data){
data.isOn = false;
System.out.println("음악 플레이어를 종료합니다.");
}
static void volumeUp(MusicPalyerData data){
data.volume ++;
System.out.println("볼륨:"+ data.volume);
}
static void volumeDown(MusicPalyerData data){
data.volume --;
System.out.println("볼륨:"+ data.volume);
}
static void showPlayer(MusicPalyerData data){
if ( data.isOn){
System.out.println("플레이어가 실행되고 있습니다.");
}else {
System.out.println("플레이어가 종료되었습니다.");
}
}
메서드를 추출하여 리펙토링하는 과정에서 다음과 같은 메서드의 장점을 발견할 수 있었습니다.
- 중복 코드 개선 : 중복되는 코드를 줄였습니다.
- 변경 사항 범위 : 변경 사항이 생겼을 때 메서드 내부의 기능만 수정해도 되어 유지 보수 면에서 개선되었습니다.
- 메서드 이름 : 메서드의 이름을 사용하여 기능의 역할을 직관적으로 알 수 있게 되었습니다.
하지만 아직까지 절차 지향적으로 작성되어 있는 것을 확인할 수 있습니다(기능, 데이터 구분되어 있음)
이는 유지 보수를 할 곳이 2곳이 되었다는 것으로 보다 효율적인 유지보수가 어려울 수 있습니다.
따라서 이후 단계에서는 기능과 데이터를 한 클래스 속에 담아 위 예시 코드보다 객체지향적인 코드가 될 수 있도록 리펙토링 해보겠습니다.
3. 클래스
⭐ 클래스 속에는 멤버변수(속성), 메서드(기능)를 모두 포함할 수 있습니다.
-MusicPlayer 클래스 생성 후 플레이어의 속성과 기능을 담아 두었습니다.
public class MusicPlayer {
//속성
int volume = 0;
boolean isOn =true;
//기능
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 showPlayer(){
if (isOn){
System.out.println("플레이어가 실행되고 있습니다.");
}else {
System.out.println("플레이어가 종료되었습니다.");
}
}
}
-main 클래스에서 객체를 생성, 클래스를 호출하였습니다.
public static void main(String[] args) {
MusicPlayer musicPlayer = new MusicPlayer();
musicPlayer.on();
musicPlayer.volumeUp();
musicPlayer.volumeUp();
musicPlayer.volumeDown();
musicPlayer.showPlayer();
musicPlayer.off();
}
메모리 그림 추가
< >
⭐플레이어의 기능과 상태를 하나의 클래스 속에 담게 되면서
수정사항이 생길 시 해당 클래스 내부에서만 수정하면 되기 때문에 절차지향적인 코드보다 유지-보수가 더욱 간편해진다는 장점을 확인할 수 있습니다.
회고
지금까지 '단순히 객체를 생성하고, 메서드를 분리하여 코드를 작성하는 것이 객체지향적인 코드이다'라고 착각하며 코딩을 했다는 것을 깨달았습니다.
코드를 리펙토링 하는 과정 속에서MusicPlayer 클래스 속 메서드는 '왜 리턴 타입만을 가지는가'에 대한 궁금증이 생겼습니다. 이에 관련하여 다음에는 static에 대해 알아보려 합니다.