객체지향의 기본개념
객체지향 프로그래밍 기초 개념
용어 정리
- 클래스
- 객체
- 인스턴스
프로그래밍 구조
- 프로퍼티와 메소드
- 캡슐화 encapsulation
- 상속 inheritance
- 다형성 polymorphism
✅ 객체 지향 프로그래밍의 의미
객체 지향 프로그래밍(Object-Oriented Programming, OOP)란 컴퓨터 프로그래밍을 순서대로 입력된 명령어의 목록이 아니라, 여러 독립적인 부품의 조합, 상호작용으로 보는 하나의 프로그래밍 패러다임을 의미한다.
객체 지향 프로그래밍은 크게 2가지 이점을 가진다. 1) 프로그램을 유연하게 설계할 수 있다. 부품과 부품의 조합에 기반한 패러다임이므로, 부품을 교체하고, 조합 방식을 교체하기에 용이하다. 2) 코드를 간결하게 표현할 수 있다. 재사용되는 부분을 하나의 부품으로 정의할 수 있기 때문이다.
그럼 객체란 무엇인가?
객체 지향 프로그래밍의 가장 기본적인 단위다. 개념적으로는 세상에 ‘모든 실재하는 대상’이라고 할 수 있다. 우리가 보는 모든 것들을 하나의 단위와 구성 요소로 만들 수 있다면 객체에 해당한다. 무형의 대상들도 포함 가능하다.
가령, Car(차)는 wheel / color / company / startEngine() / moveForward() … 등으로 객체로 정의할 수 있다. 또한, 무형의 대상인 Lesson(수업)도 student / professor / content / doExamination() … 등으로 정의할 수 있다. 이후 살펴보겠지만, 이렇게 각각의 객체를 추상화시켜 속성(state)과 기능(behavior)로 분류하고 → 이를 변수(variable)과 함수(function)로 정의할 수 있다.
객체 지향 프로그래밍의 기본적인 개념을 살펴보니, 이전에 게임 개발을 했던 것이 떠올랐다. 하나의 세계관 속에 여러 엔티티들을 정의하고 서로 어떻게 상호작용하는지 정의했던 것처럼, 세계의 모델을 프로그래밍에 녹여 풀어내는 방법으로 느껴졌다.
✅ 객체 지향 프로그래밍의 4가지 특징
객체 지향 프로그래밍은 4가지 특징을 가진다. “추상화, 캡슐화, 상속, 다형성”이다.
추상화
객체지향 프로그래밍에서는 역할과 구현을 분리한다. 즉, 객체들을 정의할 때 공통적으로 추출할 수 있는 특정 본질이 있다면 해당 공통점들을 ‘역할’로 규정해두고 → 실제적인 구현은 각각의 객체에서 담당한다. 자바에서는 이 역할 규정을 ‘인터페이스’ 또는 ‘추상클래스’로 할 수 있다고 한다. 자바스크립트에서의 실현은 뒤의 목차에서 살펴보겠다.
상속
추상화를 통해 여러 개체들이 공유하는 속성과 기능을 ‘상위 클래스’로 정의했었다. 상속은 상위 클래스를 확장하여 여러 개의 하위 클래스들이 공유된 요소들을 쉽게 활용할 수 있도록 한다. 이때, 상위클래스의 기능 및 속성을 그대로 받아서 활용해도 되지만, ‘오버라이딩’을 통해 선택적으로 재정의할 수 있다. 이는 추상화에서의 인터페이스와는 방식이 약간 다르다. 인터페이스는 상위 클래스와 달리 껍데기만 담당할 뿐, 하위 클래스에서 구체적인 구현을 강제하기 때문에, 상속이 좀더 구체성이 높다고 할 수 있다.
다형성
다형성은 어떤 객체의 속성이나 기능이 상황에 따라 여러 가지 형태를 가질 수 있음을 의미한다. 구현할 때는 메서드 오버라이딩과 오버로딩을 통해 가능하다. 이는 예시를 통해 쉽게 이해할 수 있다.
아래와 같이 껍데기의 역할을 하는 Vehicle(이동수단) 인터페이스가 있다고 하면,
Vehicle로부터 받은 같은 moveForward와, moveBackward지만 Car이라는 맥락에 맞게 다른 것을 수행한다.
좀더 중요한 정의는 아래와 같다.
객체 지향 프로그래밍에서 다형성이란 한 타입의 참조변수를 통해 여러 타입의 객체를 참조할 수 있도록 만든 것을 의미합니다. 좀 더 구체적으로, 상위 클래스 타입의 참조변수로 하위 클래스의 객체를 참조할 수 있도록 하는 것입니다.
음 이부분이 살짝 토할 것 같은데, 일단 내가 1차적으로 이해한 방식으로 서술하고 수정해보자. 위의 맥락에서 다형성은 하나의 타입만으로 여러 가지 타입의 객체를 참조”라고 하였는데, 구체적으로는 객체들 간의 결합도를 낮춰서 여러 가지 타입의 객체를 “대표”할 수 있는 더 추상적인 상위의 타입을 참조변수로 활용하는 것이라고 이해하였다.
이동수단을 운행하는 Driver 클래스가 있는 간단한 예시를 가정해보자. 다이어그램과 구현 코드 방식으로 나열한다.
// 다형성 활용 전 //
이 Driver가 운행하는 대상을 Car와 MotorBike로 바로 연결하자. 이러한 케이스를 결합도가 높은 상태라고 한다.
→ 만약 이동수단의 종류가 많아지거나, 하나의 이동수단에 대한 변경사항이 생기면 수정이 매우 불편하다.
// 다형성 활용 후 //
다형성을 활용하여 이보다 결합도가 약한, 느슨한 관계 설정을 해보자.
→ 이렇게하면 Driver클래스가 Car, MotorBike와 “간접적으로” 연결된다. 클래스 내부의 변경이나 객체가 바뀌어도 인터페이스에만 의존하여 수정하면 된다.
위의 예시 관점에서 다시 다형성을 정의해보면, 맥락에 따른 객체의 “여러 가지 형태”라는 것은 객체 간의 관계를 설정하는 데 있어서, 다양한 형태에서 적당한 결합도를 위한 형태를 선택할 수 있는 것으로 해석된다 🤔
(+) 참고로 여전히 new Car와 new MotorBike또한 객체에 직접 의존하여 결합도가 높은 상황을 보이고 있는데, 이는 스프링 프레임워크에서 의존관계 주입으로 해결한다고 한다. JS에서는 어떻게 하지?
캡슐화
캡슐화란 클래스 내부의 서로 연관 있는 속성과 기능들을 하나의 캡슐로 묶어서 외부로부터 보호하는 것이다. 자바에서는 캡슐화의 이유를 1)데이터 보호 2)데이터 은닉으로 정의한다. ‘보호’는 외부로부터 클래스에 정의된 속성.기능을 보호하는 것이며, ‘은닉’은 내부의 동작을 멈추고 외부에 필요한 부분만 노출한다.
아래의 사진처럼 알약에 비유해보자. 약의 본래 목적인 ‘치료’의 기능을 알약 안에 있는 구체적인 성분과 가루들은 알 수 없는 것이다. 단지 알약의 형태만 노출할 뿐!
사실 캡슐화는 내부 인터페이스와 외부 인터페이스의 분리 개념을 통해 이해하는 방식이 더욱 쉬웠다. 아래의 커피머신에 비유해보자. 사람이 커피머신을 사용하기 위해서는 외부의 버튼 하나만 누르면 된다. 하지만 사실 내부에서는 물이 이동하는 관, 발열장치 등이 세부적으로 구성되어있다.
커피를 타기 위해서 내부의 모든 구성 요소를 알 필요는 없다. 오히려 이에 대한 통제권을 갖는 것이 위험할 수 있다. 발열 장치를 잘못 조작하는 끔찍한 상황을 상상해보자 😱 이를 방지하기 위해 외부에서 필요한 부분만 노출시키고 나머지는 하나의 덩어리로 묶어버리는 것이다.
자, 개념은 알았으니 어떻게 실현할 수 있을까?
이는 접근제어자를 통해 달성할 수 있다. 클래스나 멤버를 외부에서 접근하지 못하도록 그 권한의 설정하는 것이다. 자바스크립트에서는 public / protected / private의 3가지 접근제어자가 있다. 자바처럼 키워드를 통해 직접 사용할 수 있는 것은 아니고 유사하게 동작할 수 있도록 하는 방식이 있다. 이는 밑에서 더욱 자세히 살펴보겠다.
| public | 내부 외부 모두 접근 가능 |
|---|---|
| protected | 같은 상속 구조에서 접근 가능 / 외부에서는 접근 불가능 |
| private | 내부에서만 접근 가능 / 같은 상속 구조여도 접근 불가능 |









