Android/학습

[CS] 객체지향 프로그래밍(OOP: Object-Oriented Programming)과 절차지향 프로그래밍(Procedural Programming)

한때미 2024. 9. 4. 01:57

 

객체지향 프로그래밍은

프로그래밍 패러다임 중 하나로,

 

OOP(Object-Oriented Programming)

객체지향 프로그래밍

객체(object)라는 개념을 중심으로 프로그램을 구조화하는 것

 

VS

 

Procedural Programming

절차지향 프로그래밍

개체를 순차적으로 처리하여 프로그램 전체가 유기적으로 연결되어 있는 것

 

 


 

OOP를 이야기할때 늘 단골로 나오는 절차지향 프로그래밍에 대한 이야기가 나온다.

하지만, 절차지향 프로그래밍과 객체지향 프로그래밍 서로 반대되는 개념이라기보다는

 

절차지향 프로그래밍이 발전하여

객체지향 프로그램이라는 패러다임이 나온 것이라고 볼 수 있다.
- 생활코딩

 

 

Procedural Programming ↔️ Object-Oriented Programming

이와 같이 표현하지만 사실은

Procedural Programming → Object-Oriented Programming

 

절차지향 프로그래밍에서 좀 더 나은 솔루션을 찾기 위한 방법 중 객체지향 프로그래밍 패러다임이 탄생했다는 의견으로,

둘은 완전 상반 관계라고 이해하는 것보다는 좀 더 쉽게 접근할 수 있다.

 


 

절차지향 프로그래밍은 프로세스데이터 별도의 모듈에 위치하며,

프로세스를 담당하는 모듈이 데이터 모듈에 모두 의존하는 형태를 띠는 형태이다.

 

 

다음은 절차지향 프로그래밍(PP) 특징을 잘 보여주는 이미지이다.

 

PP에서 필요한 Data들에 의존하여 프로세스가 동작하는 모습

 

 

 

구체적인 예시를 들면,

 

고객이 극장에서 티켓을 구매하는 로직

고객이 극장에서 티켓을 구매하는 로직을 코드로 짤 것이다.

간단하게, 고객, 직원, 티켓소가 있다고 한다.

 

코드를 한번 꼬기 위해 초대장이라는 개념을 추가하고

초대장을 가진 고객은 돈을 내지 않고 티켓을 교환할 수 있고 그렇지 않을 경우 티켓 값을 내야 한다고 하자.

 

 

대충 개념적으로 표현

 

고객은 극장에 들어가기 위해 티켓이 필요하고 해당 로직에서 극장에서 티켓을 얻는 것이 목표이다.

고객은 초대장을 가지고 있을 수도 있고 없을 수도 있다.

 

직원은 자신한테 배정된 티켓소에서 일하고 티켓소에 있는 티켓들을 고객한테 판매하여 수익을 얻는다.

 


 

이제 극장에서 고객은 표를 얻게 될 코드를 작성해 보자.

돈이 부족하고 말고 그런 예외사항은 제외하고 대충 이런 코드로 동작할 수 있을 것이다.

 

 

고객에 극장에 들어왔다.

if (고객.초대장 != null) {
	고객.초대장 = null
} else {
	고객.소지금 = 고객.소지금 - 직원.티켓소.티켓들.가격
    	직원.티켓소.돈통 = 직원.티켓소.돈통 + 직원.티켓소.티켓들.가격
}
고객.티켓 = 직원.티켓소.티켓들.pop()

 


 

해당 코드에서 절차지향 프로그램의 특징을 확인할 수 있다.

프로세스와 데이터를 별도의 모듈에 위치, 프로세스를 담당하는 모듈이 데이터 모듈에 모두 의존하는 것을 확인할 수 있다.

 

if (고객.초대장 != null) {
     고객.초대장 = null
} else {
     고객.소지금 = 고객.소지금 - 직원.티켓소.티켓들.가격
     직원.티켓소.돈통 = 직원.티켓소.돈통 + 직원.티켓소.티켓들.가격
}

고객.티켓 = 직원.티켓소.티켓들.pop()

 

어지럽습니다.

 

그냥 봐도 오만 데이터에 접근하는 것을 확인할 수 있습니다.

이 경우, 코드가 조금만 수정돼도 전체적인 코드를 수정해야 하는 대참사가 일어납니다.

 

 

예를 들어 고객의 결제수단 중 카드가 추가된다면?

오, 생각만 해도 아찔하네요

 

이거를 결합도가 높다라고 표현합니다.

 


 

그러면 해당 코드를 절차지향 프로그래밍 방식으로 수정해 보도록 합시다.

 

 

대충 개념적으로 표현

 

 

객체지향 프로그래밍 방식은 프로세스 데이터 같은 모듈에 위치하며,

각각의 객체가 자율적으로 자신의 문제를 해결하는 방식으로 문제를 해결한다.

 

 

 

 

이거를 의인화, 책임의 이동 등 관점의 차이에서 여러 이름으로 불린다.

 

 

 


여기서 책임과 역할의 차이점을 알 수 있는데,

 

 

책임은 객체가 다른 객체와 협력하기 위해 수행하는 행동이며,

역할은 객체들이 협력 안에서 수행하는 책임들이 모여 객체가 수행하는 역할인 것이다.

 

 

자신의 문제역할인 것이고

자신의 문제를 해결하는 방식책임 되시겠다.


 

 

다시 돌아와서, 객체 지향 방식으로 수정한 로직을 살펴보면 다음과 같다.

 

 

극장

fun 극장입장 (고객) {
	직원.판매하기(고객)
}

 

직원

fun 판매하기(고객) {
	티켓소.현금추가(고객.구매하기(티켓소.티켓 가져오기))
}

 

고객

fun 구매하기(티켓): Long {
	if (초대장확인()) {
    	내 티켓 = 티켓
    	return 0
    } else {
    	내 티켓 = 티켓
        지출(티켓.가격조회())
        return 티켓.가격조회()
    }
}

 

 

음, 좋습니다.

각 객체들은 서로의 인터페이스에 대한 접근으로 결합도를 낮추고

각자의 역할을 통해 응집도를 높였군요.

 


 

직원은 티켓을 고객에게 판매하는 역할을 수행합니다.

자신이 일하고 있는 티켓소의 티켓을 고객에게 판매하여 현금을 추가하는 책임이 있습니다.

fun 판매하기(고객) {
	티켓소.현금추가(고객.구매하기(티켓소.티켓 가져오기))
}

 

 

고객은 티켓을 구매하는 역할을 수행하네요.

내 초대장을 확인해서 티켓을 교환하거나 돈을 내고 티켓을 교환할 책임을 가지고 있군요.

fun 구매하기(티켓): Long {
	if (초대장확인()) {
    	내 티켓 = 티켓
    	return 0
    } else {
    	내 티켓 = 티켓
        지출(티켓.가격조회())
        return 티켓.가격조회()
    }
}

 

 

극장은 직원이 고객에게 티켓을 판매하는 장소군요!

fun 극장입장 (고객) {
	직원.판매하기(고객)
}

 


 

 

직접 구체적인 로직으로 풀어볼 때, 

처음 본 코드에 비해 개선된 코드는 각 역할 별로 행동이 정해져 있어 더 이해하기 쉽습니다.

 

각 객체가 각자의 역할로 책임을 수행할 때,

응집도는 높아지고 각 객체들끼리의 결합도는 낮아집니다.

 

 

이렇게 코드를 수정할 경우 추후 수정에도 유연하게 대응할 수 있을 것 같네요.

 

 

또!

 

 

객체 지향적으로 프로그래밍할 때,

코드에 대해 직관적으로 이해하기 쉽다고 느껴지지 않나요?

 

 

 

 

 

 

출처: 코드로 이해하는 객체지향 설계, 오브젝트

 

극장 예시는 오브젝트 교재를 참고하였으며, 해당 교재에서 좀 더 구체적인 예시와 실제 코드를 확인할 수 있습니다.