객체 지향 프로그래밍 1편 - 간단한 설명과 예시

2024. 3. 4. 22:29Development

오늘은 객체 지향 프로그래밍에 대해 이야기 해 보려고 해요.


1. 객체 지향 프로그래밍이란?

2. 객체 지향 프로그래밍의 예

3. 객체 지향 프로그래밍의 특징

4. 객체 지향 프로그래밍을 이용하여 간단한 API 작성하기


1. 객체 지향 프로그래밍이란? - What is OOP?

오늘은 객체 지향 프로그래밍(Object Oriented Programming)이라는 개념을 들어보셨나요?

프로그래밍을 하고 있다면 한 번 쯤은 들어본 용어일테지만, 상당히 추상적이어서 단번에 이해하기 어렵습니다.

 

서비스의 규모가 커지면서, 프로젝트는 점점 복잡해졌고, 이를 체계적으로 설계하고 관리할 필요성이 생겼습니다.

객체 지향 프로그래밍은 특히 규모가 큰 프로젝트에 적합하며, 개발 생산성에 큰 도움을 주었습니다.

 

그러면 객체 지향 프로그래밍이 무엇일까요?

 

제가 이해하는 객체 지향 프로그래밍은 모든 데이터를 객체로 표현하고, 이 객체들의 상호작용으로 프로그램을 실행하는 것이라고 생각합니다.

 

객체 지향 프로그래밍은 프로그램을 어떻게 구현할 것인가에 초점을 두기 보단, 객체들이 어떻게 상호작용하는가에 초점을 맞춥니다.

즉 "돌아가면 그만이지"라는 사고 방식에서 벗어나, 어떻게 하면 체계적으로 잘 돌아가게 할 지 고민해야 합니다.

 

각 객체는 독립적인 역할을 갖고, 본인의 역할만 처리하면 되며, 나머지 역할은 다른 객체에게 넘겨버립니다.

따라서 객체 지향 프로그래밍의 원칙에 따라 잘 설계 되었다면, 문제가 생겼을 때 문제가 생긴 하나의 객체만 수정하면 쉽게 유지보수를 할 수 있습니다.


2. 객체 지향 프로그래밍의 예 - Simple Example

예를 들어, 사용자의 로그인 요청을 처리해야 한다고 가정해봅시다.

로그인을 하기 위해 어떤 정보가 필요할까요?

 

기본적으로 아이디와 비밀번호가 필요하겠죠?

사용자의 요청을 받는 login 함수와 사용자 정보 확인, 비밀번호 확인 등 여러 로직을 담고 있는 process_login 함수가 있다고 가정해볼게요. 그러면 아래와 같이 함수를 작성해볼 수 있어요.

 

def login(username: str, password: str):
	return process_login(username, password)

def process_login(username: str, password: str):
	user = check_user(username)
    	return check_password(user, password)

(실제로 로그인 로직은 더욱 복잡하니 이해 용도로만 봐주세요!)

 

여기서 추가 요청으로 인해, MFA(Multi Factor Authentication)를 적용하게 됐어요.

따라서 휴대폰으로 받은 인증 번호도 인증 로직에 추가해야 해요.

def login(username: str, password: str, code: str):
	return process_login(username, password)

def process_login(username: str, password: str, code: str):
	check_code(username, code)
	user = check_user(username)
    	return check_password(user, password)

 

인증을 위해 필요한 데이터가 변경된다면 이와 관련된 함수의 인자를 모두 수정해줘야 해요.

지금은 간단한 예시이기 때문에 두 개의 함수만 수정해도 됐지만, 실제로는 더 많은 함수가 상호작용하기 때문에 프로젝트의 규모가 커질 수록 문제가 되겠죠?

 

그러면 로그인 요청을 담고 있는 데이터를 객체로 만들어 두 함수를 다시 작성해볼게요.

class loginRequestDto:
    username: str
    password: str
    code: str
def login(login_request_dto: loginRequestDto):
	return process_login(login_request_dto)

def process_login(login_request_dto: loginRequestDto):
	check_code(login_request_dto.username, login_request_dto.code)
	user = check_user(login_request_dto.username)
    	return check_password(user, login_request_dto.password)

 

참고로 데이터를 주고 받을 때 이를 담는 객체를 DTO(Data Transfer Object)라고 해요.

DTO는 데이터 필드와 접근 메소드로만 구성되어 있는 가벼운 객체예요.

 

위와 같이 작성하면, DTO의 구조만 바꿔주면 로그인 로직을 바꿀 수 있어요.

위 예시는 객체 지향 프로그래밍을 보여드리기 위해 다소 억지로 상황을 만든 감은 있지만, 객체 지향을 사용해야 하는 이유에 대해선 설명이 된 것 같아요.

 

다른 예시로, 객체 지향 프로그래밍의 특징을 이용하여 정다각형(Shape) 객체를 만들어볼게요.

class Shape:
	color: str
    	perimeter: int
    
    	def length(self):
        	raise NotImplementedError()

class Triangle(Shape):
	def length(self):
    		return super().perimeter // 3

class Rectangle(Shape):
	def length(self):
    		return super().perimeter // 4

 

Shape 클래스는 색깔과 둘레라는 공통 데이터를 가지고 있고, length 함수로 한 변의 길이를 반환하는 함수가 있어요.

 

삼각형(Triangle)과 (Rectangle)에서 Shape 클래스를 상속받아 도형이 가지는 특징인 색깔과 둘레 데이터를 가질 수 있도록 했어요.

하지만 정다각형마다 한 변의 길이를 구하는 방식이 다르기 때문에 length 함수는 각 도형에서 구현해주었어요.

 

객체의 공통 성질을 추출하여 한 클래스로 만들고, 이를 상속하게 만들면 후에 도형에 대한 정보가 수정되어도 부모 클래스(Shape)만 수정하면 이를 상속하는 클래스에도 모두 적용이 돼요.

 

따라서 별 수고를 들이지 않고 데이터를 수정할 수 있겠죠?

 

위 두 예시에서 볼 수 있는 공통점은 확장에 유리하게 설계를 한다는 거예요.

확장에 용이하다는 장점 뿐만 아니라 더 많은 장점이 있기 때문에 다음 글에는 객체 지향의 특징을 통해 왜 객체 지향 프로그래밍을 해야 하는지 알아볼게요.


제 글이 많은 도움이 되었길 바라며,
긴 글 봐주셔서 감사합니다!
멋진 개발자가 되기 위해 더 열심히 달리겠습니다!
- 달맹 -