𝝅번째 알파카의 개발 낙서장

screen

[OOP] 객체지향 프로그래밍(Object Oriented Programming)이란?

posts

CS

시리즈 톺아보기

객체지향

객체지향
count

OOP 🔗

IT 업계에 종사하게 된다면 십중팔구 JAVA, C++, C# 중 하나는 다루게 된다. 국내 IT의 최다 공급이자 수요인 JAVA를 위시한 위 세 가지 언어의 공통점은 전부 객체지향언어라는 점이다.

물론 지금에 이르러서는 함수형이라는 개념도 나왔지만, C의 단순한 절차지향 이래로 나온 객체지향은 프로그래밍의 새로운 관점을 제시했고, 크고 작은 언어들이 알게 모르게 영향을 받았다. 이렇게 영향력이 큰 개념임에도 불구하고 막상 이와 관련된 질문을 받으면 명확하게 답을 내지 못 하기도 한다.

객체지향에 대해 설명해보세요. 🔗

제목 그대로 위와 같은 질문을 받았다고 가정해보자. 난 이 질문의 명확한 답을 주지 못 한다. 자바 경험이 없지 않음에도 불구하고, 이론에는 크게 관심이 없기도 했고, 비전공자인 난 구태여 찾아보지 않는 이상 이와 같은 내용을 실무에서 습득하긴 어려웠다.

내가 쓰는 언어가 어떤 방식으로 동작하는지 모른다면 그건 제대로 쓴다고 보긴 어렵다. 이 주제를 통해 객체지향의 개념에 대해 정리해보고자 한다.

객체 🔗

객체지향. 말 그대로 객체를 지향하는 언어다. 객체지향에 대해 이해하기 위해선, 일단 이 방법론이 궁극적으로 지향하는 객체란 개념에 대해 이해할 필요가 있다.

객체지향이 말하는 객체란 프로그램 동작의 주체가 되는 요소를 의미한다. 이 객체는 유/무형을 가리지 않는다. 실체가 명확한 것일 수도 있고, 무형의 개념일 수도 있다.

모든 객체는 상태와 동작을 가진다. 예를 들어, TV를 구매한다고 생각해보자. 대부분의 사람들은 TV의 디자인, 성능, 가격 등을 적절히 고려하여 TV를 구매할 것이다.

TV의 색, 인치, 가격 등은 TV가 가진 상태라고 볼 수 있다. TV 채널 이동, 다시 보기, 넷플릭스 연결 등은 TV의 기능이라고 볼 수 있다.

이렇게 모든 객체에는 상태동작이 존재한다.

국내 객체지향 언어의 대표격인 JAVA는 이러한 개념을 아래와 같이 접근한다.

객체지향 JAVA
객체 클래스
상태 멤버 변수
동작 메소드 (함수)

여기 자동차라는 현실의 객체를 JAVA가 어떻게 클래스로 다루는지 예제를 통해 알아보자.

JAVA

0/**
1 * 자동차 클래스
2 *
3 * @author RWB
4 * @since 2021.08.05 22:06:24
5 */
6public class Car
7{
8 // 시동 여부
9 private final boolean IS_STARTED = false;
10
11 // 최대 속력
12 private final int MAX_SPEED;
13
14 // 현재 속력
15 private int speed;
16
17 /**
18 * Car 생성자 함수
19 *
20 * @param maxSpeed: [int] 최대 속도
21 */
22 public Car(int maxSpeed)
23 {
24 MAX_SPEED = maxSpeed;
25 }
26
27 /**
28 * 시동 결과 반환 함수
29 *
30 * @return [boolean] 시동 결과
31 */
32 public boolean startUp()
33 {
34 return !IS_STARTED;
35 }
36
37 /**
38 * 시동 종료 결과 반환 함수
39 *
40 * @return [boolean] 시동 종료 결과
41 */
42 public boolean shutdown()
43 {
44 return IS_STARTED;
45 }
46
47 /**
48 * 현재 속도 반환 함수
49 *
50 * @return [int] 현재 속도
51 */
52 public int getSpeed()
53 {
54 return speed;
55 }
56
57 /**
58 * 가속 함수
59 *
60 * @param amount: [int] 속도
61 */
62 public void upSpeed(int amount)
63 {
64 // 시동이 걸렸을 경우
65 if (IS_STARTED)
66 {
67 // 가속된 값이 최대 속도를 넘지 않을 경우
68 if (MAX_SPEED >= speed + amount)
69 {
70 speed += amount;
71 }
72
73 // 가속된 값이 최대 속도를 넘을 경우
74 else
75 {
76 speed = MAX_SPEED;
77 }
78 }
79 }
80
81 /**
82 * 감속 함수
83 *
84 * @param amount: [int] 속도
85 */
86 public void downSpeed(int amount)
87 {
88 // 시동이 걸렸을 경우
89 if (IS_STARTED)
90 {
91 // 감속된 값이 0보다 클 경우
92 if (0 <= speed - amount)
93 {
94 speed -= amount;
95 }
96
97 // 감속된 값이 0보다 작을 경우
98 else
99 {
100 speed = 0;
101 }
102 }
103 }
104}

위의 코드 Car 클래스는 자동차라는 현실의 객체를 매우 간단한 형태로 구현한 클래스다.


  • 멤버 변수 (상태)
    • IS_STARTED 자동차 시동 여부
    • MAX_SPEED: 최대 속도
    • speed: 현재 속도

  • 메소드 (동작)
    • startUp: 엔진 시동
    • shutdown: 엔진 정지
    • getSpeed: 현재 속도 표시
    • upSpeed: 가속
    • downSpeed: 감속

Car 클래스의 요소는 위와 같이 구분된다. JAVA에서 이 객체를 사용하려면 메모리에 할당해야하고, 이렇게 할당된 객체를 인스턴스(Instance)라 칭한다.

Car 클래스를 메모리에 할당하여 새로운 인스턴스를 만드는 것은 현실에서 자동차 하나를 뽑는 것과 동일한 개념이다.

객체지향 🔗

객체지향이므로, 앞서 언급했듯이 이를 이해하기 위해선 객체를 이해해야한다. 이미 이전 문단에서 객체에 대해 장황하게 설명했으므로, 객체지향은 이러한 객체를 통해 코드를 구성하는 방법론이라 정의할 수 있다.

모든 객체는 각 객체의 특성에 부합하는 상태와 동작을 가지며, 이를 통해 객체 간의 상호작용을 코드로 나타낼 수 있다. 객체지향은 이러한 객체의 상호작용을 코드로 나타낸다.

일례로 JAVA는 String, HashMap 등, 모든 요소를 객체(Object)로 다룬다. 우리는 JAVA로 필요한 객체를 메모리에 할당하고, 객체가 가진 변수나 메소드를 사용하여 코딩한다. 이러한 JAVA의 프로그래밍 방식은 지금껏 설명한 객체지향의 그 것과 동일함을 알 수 있다.

그래서 이걸 왜 쓰는데? 🔗

객체지향을 차용한 언어는 매우 많다. 대표격인 JAVA 이외에도 C++, C#, Visual Basic, Swift, Python 등이 있다. 또한 이 언어들은 우리에게 매우 익숙한 이름일 뿐만 아니라, 프로그래밍 언어에서 다들 한 자리씩은 차지하는 매우 비중있는 언어들이다.

그렇다면 객체지향 언어가 개발자들에게 그토록 널리 쓰이며, 사랑받을 수 있었던 이유는 무엇일까?

객체지향은 절차지향의 후발주자다. 보통 이런 경우의 후발주자는 선발의 단점 혹은 니즈들을 개선하여 출시하므로 기능 혹은 편의성에서 많은 이점을 가진다. 객체지향은 특히 생산성과 유지보수 용이성을 높이는 데 포커스를 두었으며, 덕분에 객체지향 언어를 구사하는 개발자는 개발을 비교적 쉽고 빠르게 수행할 수 있다.

장점 🔗

  • 코드 재사용성
    모듈화된 객체를 기반으로 코드가 작성되기 때문에, 해당 객체의 특징을 비슷한 다른 로직에도 적용해서 사용하거나, 다른 개발자가 구현한 객체를 가져와 쓰기에도 용이하다.

  • 간편한 유지보수
    객체를 수정할 경우, 해당 객체를 사용하는 모든 로직에 일괄적으로 적용되니, 중복 코드에 대한 관리가 간단해진다. 혹은 객체나 동작이 변경될 경우, 해당 객체나 동작과 연관된 객체만을 찾아 수정하면 된다.

  • 큰 규모의 프로그래밍에 유리
    객체, 모듈 단위로 구분되는 특징으로 인해 업무 분장이 쉽고, 각 모듈의 연관성을 도식하기 용이하다.

단점 🔗

  • 비교적 느린 속도
    절차지향과 달리 객체지향은 각 객체의 의존 관계로 인해 대체적으로 속도가 느리다.

  • 높은 설계역량 요구
    모듈 단위의 상호작용으로 이루어진 방식은, 모듈의 정확한 명세와 상호 간의 연관성이 얼마나 짜임새있게 설계되었는지 중요하다. 잘 못 설계된 객체나 연관성은 라쟈나 코드로 변하기 쉽다.

  • 코드의 잠재적인 복잡성
    높은 수준의 설계역량 요구와 더불어 추상 객체, 상속, 인터페이스 등의 복잡한 개념과 그 활용은 코드의 구조를 파악하기 어렵게 만든다.

객체지향을 사용하는 언어들 🔗

  • JAVA
  • C++
  • C#
  • Python
  • Simula 67
  • Delphi
  • Swift
  • Ruby
  • Perl

대부분 아는 얼굴들이구만

정리 🔗

기존의 C언어의 기반인 절차지향도 나름의 장점이 있었다. 컴퓨터의 처리 흐름과 코드의 흐름이 매우 유사하기 때문에 전처리가 적어 실행 속도가 비교적 빨랐다. 또한 코드의 흐름이 일정했으므로, 이를 분석하기도 수월했을 것이다.

하지만 시대가 지남에 따라 시대가 발전했고, 개발자의 평균 역량 또한 높아졌다. 컴퓨터의 처리 속도는 언급할 필요조차 없었고. 이러한 환경의 발전으로 인해 절차지향의 장점이 주는 메리트가 적어지면서, 반대로 단점이 주는 디메리트가 더더욱 크게 다가왔을 것이다.

객체지향은 유지보수의 용이성과 개발 편의성을 중요시 여기는 개발 방법론이다. 객체지향이 가지는 장점 덕분에 개발자 간의 코드 공유가 쉬워졌으며, 서비스의 규모는 더욱 증가하고, 견고한 프로그램을 만들기 쉬워졌다.

절차지향이 컴퓨터에게 친화적이라면, 객체지향은 개발자에게 친화적이라 할 수 있겠다. 컴퓨터의 성능이 미친듯이 높아짐에 따라, 프로그램의 성능은 자연스레 개발자의 역량에 갈리게 됐다. 이러한 흐름으로 인해 객체지향은 많은 언어, 개발자에게 사랑받을 수 있었을 것이다.

요즘 AI 기술이 발달함에 따라 Copilot 등 AI가 코딩을 보조해주는 기술이 연구되고, 등장하고 있는 것 같다.

나중에 시간이 지나 개발자의 역량이 더 이상 중요하지 않게 되면 새로운 방법론이 대세가 되지 않을까?