10월 27일 일요일 본 캠프 개발 일지 | 객체지향 프로그래밍 특강
📌
개인 과제를 필수 기능 구현을 위해 강의에서 이해 되는 코드를 옮겨쓰는 와중, 아이템 데이터 관리를 앞두고 작업을 멈췄다. 코드의 뜻은 알아도 클래스 간의 연결, 즉 프로그래밍을 완벽히 숙지하지 못 한 게 마음에 걸렸기 때문이다. 제일 답답한 부분이기도 하고, 금요일에 10% 정도 알게 되었던 객체지향을 정리하기 위해 블로그를 켰다.
※ 주의: 틀린 거 많을 수도 있음. 주관적임.
학습 내용
1. 객체지향 프로그래밍
2. 객체지향 프로그래밍 설계하기
3. 객체지향 프로그래밍 실전
4. 참고 자료
1. 객체지향 프로그래밍
✅ 절차지향과 객체지향이란?
절차지향: 프로그램을 일련의 단계적 절차나 함수의 흐름으로 구성하여 실행해 작업을 수행하기 위한 논리를 순차적으로 작성하는 방식
객체지향: 프로그램을 독립된 객체(Object)들의 모임으로 구성하고 이 객체들 간의 상호작용을 통해 기능을 수행하도록 만드는 접근 방식
실제로 어떤 기능을 구현해 한다고 했을 때 둘의 코드 방식을 비교해보자.
반 청소
public class 반 청소
{
public void CleanClassroom()
{
StartCleaning();
ArrangeDesks();
CleanFloor();
CleanBoard();
EmptyTrash();
CloseWindows();
}
private void StartCleaning() { /* 청소 시작 */ }
private void ArrangeDesks() { /* 책상 정리 */ }
private void CleanFloor() { /* 바닥 청소 */ }
private void CleanBoard() { /* 칠판 지우기 */ }
private void EmptyTrash() { /* 쓰레기통 비우기 */ }
private void CloseWindows() { /* 창문 닫기 */ }
}
절차지향 프로그래밍의 경우, 반 청소라는 클래스 내에서 여러 개의 순서대로 진행되는 단계를 구성하게 된다.
public interface ICleanable
{
void Clean();
}
public class Desk : ICleanable
{
public void Clean() { /* 책상 정리 로직 */ }
}
public class Floor : ICleanable
{
public void Clean() { /* 바닥 청소 로직 */ }
}
public class Board : ICleanable
{
public void Clean() { /* 칠판 지우기 로직 */ }
}
public class TrashBin : ICleanable
{
public void Clean() { /* 쓰레기통 비우기 로직 */ }
}
public class Window : ICleanable
{
public void Clean() { /* 창문 닫기 로직 */ }
}
객체지향의 경우, 반 청소에 필요한 각 단계와 기능들을 독립적인 객체로 바라보며 각 객체 간의 상호작용으로 '청소'를 진행하게 된다.
✅ 그래서 왜 객체지향 프로그래밍을 써야할까?
만약 반 청소가 학교 전체 청소로 바뀐다고 하자. 절차지향을 사용했을 경우, 각 반마다 클래스를 새롭게 구성해야 하지만 정작 메서드는 중복되는 게 많을 것이다. "쓰레기통 비우기"라는 단계를 매번 추가해줘야 하고 만약 "쓰레기통 비우기"라는 단계에 수정 사항이 생긴다면 모든 클래스에서 "쓰레기통 비우기"를 찾아서 수정해야 하는 수고스러움이 생긴다. 그뿐일까? 청소의 순서가 바뀐다면 일일히 메서드를 수정하면서 오류가 생길 가능성이 높다.
반면 객체지향 프로그래밍은 각 객체가 자신만의 Clean 메서드를 통해 독립적으로 청소 방식을 구현하고 있기 때문에 이와 같은 단점을 상쇄할 수 있다. 장점을 정리해보면 다음과 같다.
- 유연성: 객체의 청소 방식을 수정해도 다른 객체에 영향을 주지 않으며, 청소 순서도 쉽게 변경할 수 있다.
- 확장성: 청소할 다른 객체나 작업이 추가되더라도 코드를 재사용하며 유연하게 확장할 수 있다.
그러니까 객체지향은 일종의 블록 쌓기이다. 블록을 결합해서 쉽게 새로운 형태를 만들고, 블록을 추가해서 확장할 수 있고, 제거 또한 간편하다. 더군다나 중복되는 코드를 줄여서 메모리까지 효율적으로 관리할 수 있다는 것!
2. 객체지향 프로그래밍 설계
✅ 객체
모든 객체는 속성과 기능으로 표현할 수 있다. 이때 속성은 변수이고, 기능은 함수(메서드)로 볼 수 있다.
플레이어 객체
속성: HP, MP, 스태미나
기능: 이동(), 공격(), 스킬()
물론 이때의 '기능'도 하나의 객체가 될 수 있다.
이동 객체
속성: 이동 속도, 이동 방향, 이동 이펙트
기능: 이동()
공격 객체
속성: 공격 속도, 공격 방향, 데미지 값
기능: 공격(), 데미지()
그럼 객체 지향은 기능을 쪼갤 수 있는 만큼 세분화한 클래스를 만드는 걸까?
반쯤은 맞고 반쯤은 다르다. 객체지향은 기능을 세분화할 수 있는 만큼 세분화하는 것이 아니라, 효율적이고 명확하게 책임을 나누어 설계하는 것을 목표로 한다. 필요할 때 공통된 책임(공통 분모)을 묶어 상호작용을 유연하게 처리하는 구조를 만드는 것이 객체지향의 핵심이다.
플레이어가 아닌 실제 존재하는 인간으로 예시를 들어보자.
인간은 객체지향적인 행동을 하면서 살고 있다. "일어나서 세수하기"라는 행동을 할 때 일어나기, 걷기, 세수하기를 별도의 행동으로 생각하고 있기 때문에 중간에 장애물이 있거나 통화가 울려도 넘어지지 않고 행동을 계속할 수 있다. 이러한 맥락에서 "앉는다"는 행동을 한다고 생각해보자. 쭈구려 앉기, 양반다리로 앉기, 정자세로 앉기 등 다양한 앉는 자세가 "앉기"는 공통 분모로 묶여있기 때문에 "앉는다"는 명령어 하나로 수행이 가능한 것이다.
✅ 객체지향 프로그래밍의 4가지 특징
객체지향 프로그래밍을 설계하기 위한 큰 맥락은 다음과 같다.
[1] 객체는 기능을 제공한다.
[2] 기능을 제공하기 위해 캡슐화 한다.
[3] 캡슐화 하기 위해 추상화 한다.
📝