개발을 막 시작한 새내기 개발자부터 개발 경력이 많은 개발자까지 무조건 들어봤을 용어, 객체 지향에 대해 알아보자.자동차 운전을 코드로 구현하는 것을 예시로, 객체 지향과 절차 지향을 비교해 가면서 설명한다. 객체 지향을 배우러 왔는데, 절차 지향까지 알아야 한다고 겁먹지 말자, 절차 지향을 이해한다면, 객체 지향을 이해하기 더욱 쉬울 것이다.이 내용은 기본적인 코드 작성 지식이 있어야 이해할 수 있다.
절차 지향과 객체 지향
절차 지향이란?
객체지향이 있기 이전, 개발 패러다임은 절차 지향이었다. 절차 지향은 간단히 “어떤 일을 하기 위해 필요한 행동들의 나열” 이라고 정의할 수 있다. 아래와 같은 코드 예제를 보자
def main():
direction = input("핸들을 어느 방향으로 돌릴 것 인가요?(left, right): ")
if direction == "right":
print("핸들을 오른쪽으로 전환!")
else:
print("핸들을 왼쪽으로 전환!")
main()
사용자에게 핸들 방향을 입력받고, 해당 방향에 맞게 핸들을 돌렸다고 출력해 주는 코드이다.
이와 같이, “핸들을 꺾기 위해(어떤 일) 사용자의 입력을 받고, 입력에 맞게 문자열을 출력하는 코드 (행동들의 나열)“로 볼 수 있는 것이 절차 지향적인 코드 작성 방법이다.
객체 지향이란?
객체 지향은 절차지향의 정의인 “어떤 일을 하기 위해 필요한 행동들의 나열"을 확장해서 “어떤 일을 하기 위한 객체들의 상호작용"으로 정의할 수 있다. 아래와 같은 코드 예제를 보자
class Car:
def chagne_direction(self, direction: string):
if direction == "right":
print("핸들을 오른쪽으로 전환!")
else:
print("핸들을 왼쪽으로 전환!")
def main():
direction = input("핸들을 어느 방향으로 돌릴 것 인가요?(left, right): ")
car = Car()
car.chagne_direction(direction)
main()
우선 Car라는 클래스를 만든다. 해당 클래스에서는 자동자의 “행동"과 관련된 모든 것을 다룬다. 여기에서는 방향전환 행동만을 추가했다.
그리고 절차 지향에서의 코드와 같이 사용자에게 입력을 받고, 해당 입력을 저장해 둔다.
이후, Car(클래스)에서 car(인스턴스)를 만들고, car(인스턴스)의 change_direction을 실행해서 핸들을 전환하도록 한다.
이와 같이 자동차라는 개념적인 그룹으로 묶어서 코드를 작성하는 방식을 객체 지향 개발이라고 한다.
클래스와 인스턴스
클래스/인스턴스는 처음 마주했을 때 이해하기 쉽지 않은 용어이다.
자동차를 예로 들어보자.
자동차는 어떤 것인가? 명확히 정의하긴 어렵지만, 바퀴 4개(혹은 더 여러 개), 엔진, 핸들이 있는 탈 것이라고 할 수 있다. 이런 개념적인 것들을 가진 모든 것들을 자동차라고 부를 수 있다. 이렇게 보면, 완전히 추상적인 개념이라고 볼 수 있다. 이런 것들을 클래스라고 한다.
우리가 실제 이용하는 자동차들은 무엇이 있을까. 나의 산타페, 다른 사람의 산타페, 602-1A번 버스 등 많은 자동차들이 있다. 이런 것들을 인스턴스라고 한다.
자동차라는 “개념"만 가지고는 행동을 할 수 없지만, 산타페라는 실체를 가지고는 운전을 할 수 있다. 이처럼 행동을 할 수 있도록 클래스에서 객체를 만들어서 사용한다.
아래와 같은 코드 예제를 보자
class Car:
def chagne_direction(self, direction: string):
if direction == "right":
print("핸들을 오른쪽으로 전환!")
else:
print("핸들을 왼쪽으로 전환!")
def main():
# car1과 car2는 Car에서 생성된 두개의 다른 실체임
car1 = Car()
car2 = Car()
main()
이 코드는 Car클래스에서 두 개의 인스턴스를 생성한다.
다르게 이야기하면, 하나의 Car라는 추상적인 개념에서 두 대의 실제 자동차를 생성한 것이고, 이 자동차들을 각자 개별적으로 움직일 것이다.
정리하자면,
클래스는 “어떤 행동을 하는 추상적인 개념 - 자동차, 사람”
**인스턴스는 “실제로 그 행동을 하는 실체 - 산타페(자동차), 나 자신(사람), 여러분들(사람)”**으로 정리할 수 있겠다.
객체와의 상호작용
이번엔 객체 지향 프로그래밍의 본질인, 객체와의 상호작용을 알아보자.
이번에도 코드 예제를 보도록 하자.
class Wheel:
def change_direction(self, direction: string):
if direction == "right":
print("바퀴를 오른쪽으로 전환!")
else:
print("바퀴를 왼쪽으로 전환!")
class Car:
def __init__(self):
self.wheel = Wheel()
def chagne_direction(self, direction: string):
if direction == "right":
print("핸들을 오른쪽으로 전환!")
else:
print("핸들을 왼쪽으로 전환!")
self.wheel.change_direction(direction)
def main():
direction = input("핸들을 어느 방향으로 돌릴 것 인가요?(left, right): ")
car = Car()
car.chagne_direction(direction)
main()
main 함수는 위의 예제와 같다.
이번에 추가된 것은 Wheel의 존재다. 잘 생각해 보면, 자동차는 바퀴가 있어야 굴러갈 것이다. 그리고 사용자가 핸들을 돌리면 바퀴가 돌아가야 할 것이다. 그러므로 Car는 Wheel을 가지고 있어야 한다. (이것을 has-a 관계라고 하는데, 이 부분은 나중에 설명하겠다)
그래서 위의 예제는 사용자가 핸들을 돌리면 바퀴도 같이 돌아가는 예제이다.
Car는 처음 생성될 때, Wheel을 생성해서 자신이 가지고 있고, 사용자가 핸들을 돌리면, Car는 Wheel의 방향을 변경한다.
이렇게 보면 Car와 Wheel이 상호작용하고 있는 것을 볼 수 있다.
만약 절차 지향적인 코드였다면 어땠을까?
def main():
direction = input("핸들을 어느 방향으로 돌릴 것 인가요?(left, right): ")
if direction == "right":
print("핸들을 오른쪽으로 전환!")
print("바퀴를 오른쪽으로 전환!")
else:
print("핸들을 왼쪽으로 전환!")
print("바퀴를 왼쪽으로 전환!")
main()
위와 같이 끝났을 것이다.
어라 근데 여기서 이상한 점이 보인다.
절차 지향이 더 좋아 보이는데…?
필자가 제시한 예제를 보면, 절차지향적인 코드가 훨씬 짧고 간결해 보이고, 이해하기도 쉬워 보인다.
하지만 다들 실제로 객체지향적으로 구현을 하고 있다.
이유가 뭘까?
이유는 재사용성이다.
만약 자동차가 100대가 동시에 움직인다면?
저 if-else 부분을 100번 돌리는 것이 좋을까? Car를 100개 만드는 게 좋을까?
직관적으로 봤을 때, Car를 100개 만드는 것이 다른 사람이 볼 때 더욱 이해하기가 쉽지 않을까?
하지만 더욱 중요한 이유가 있다.
다른 사람과의 협업을 고려하자.
개발은 혼자 할 수 도 있지만 여러 명과 같이 할 수도 있다.
클래스로 짜놓으면, 누가 봐도 ‘아 이 부분은 자동차를 구현하려고 한 거구나’를 알 수 있다.(주석 없이도!) if-else 문을 100번 반복한다고 했을 때, 같이 협업하는 사람이 보면 과연 이 코드를 제대로 이해할까? 필자였다면, 머릿속에 물음표만을 띄웠을 것이다.
그런 면에서 봤을 때, 객체 지향 프로그래밍이 많이 쓰이는 이유를 알 수 있을 것이다.
맹신은 금물.
어느 패러다임이 항상 정답은 경우는 없다. 객체 지향이 무조건 옳지도 않고, 상황에 따라 절차 지향적으로 개발하는 것이 더 좋을 때도 있다.
항상 요구사항에 맞게 개발하는 것이 중요하다. 무조건적인 적용은 오히려 협업을 방해할 수도 있다는 것을 명심하자.
마무리하며
오늘은 객체 지향에 대해 설명해 보았다. 필자도 객체지향에 대해 설명하면서, 알고 있다고 생각했지만 머릿속에 막연히 있는 개념을 글로 풀어내는 것이 참 어렵다고 느낀다. 이 개념을 처음 접하는 분들도 이해하지 못한 부분이 있을 것이라고 생각한다. 그런 부분이 있다면 댓글로 물어봐주시길 바란다.