객체 지향 프로그래밍 (Object Oriented Programming)에 대해 알아보자!
현대의 언어들은 객체 지향의 특징을 갖고 있다. 그렇다면 예전에는 어땠을까?
절차적 언어
- 초기의 프로그래밍 언어는 일반적으로 절차적 언어라고 불렀다.(C, 포트란 등)
- 순차적인 명령의 조합으로 이루어져있다.
그러나, 객체 지향 프로그래밍이라는 패러다임이 등장하면서, 단순히 별개의 변수와 함수로 순차적으로 작동하는 것을 넘어, 데이터의 접근과, 데이터의 처리 과정에 대한 모형을 만들어 내는 방식을 고안해냈다. 바로 객체 지향 프로그래밍!(Object Oriented Programming)
객체 지향 언어
- “클래스”라고 부르는 데이터 모델의 청사진을 사용해 코드 작성
- 현대의 언어들은 대부분 객체 지향의 특징을 가지고 있음(대표적으로 java, c++, c# 등)
- javascript: 객체 지향으로 작성 가능
- 데이터와 기능이 별개로 취급되지 않고, 한 번에 묶여서 처리할 수 있게 되었다
- 자바스크립트는 엄밀히 말해 객체 지향 언어는 아니지만, 객체 지향 패턴으로 작성할 수 있음
그렇다면 OOP란 무엇일까?
OOP
- 프로그램 설계 철학
- 모든 것은 "객체"로 그룹화됨
- 4가지 주요 개념을 통해 재사용성을 얻을 수 있음
OOP는 프로그램 설계 철학 중 하나이다. OOP는 객체로 그룹화된다. 이 객체는 한번 만들고 나면, 메모리상에서 반환되기 전까지 객체 내의 모든 것이 유지된다.
객체 내에는 "데이터와 기능이 함께 있다"라는 원칙에 따라 메서드와 속성이 존재한다.
예를 들어보자!
모든 자동차는 공통적인 기능과 고유의 속성이 있는데 속도를 낸다든지, 주유를 한다든지 등의 기능이 존재하며, 속성으로는 색상, 최고 속력 혹은 탑승인원 등과 같은 고유의 데이터가 존재한다. 새로운 객체를 만들 때, "이번에 만들 자동차는, 빨간색의 최고 속력은 200km/h를 내도록 만들어보자!"와 같이, 속성에 고유한 값을 부여할 수 있다.
그렇다면 위에서 언급한 객체 지향 프로그래밍의 4가지 주요 개념은 무엇일까?
객체 지향 프로그래밍의 4가지 주요 개념
- Encapsulation (캡슐화)
- Inheritance (상속)
- Abstraction (추상화)
- Polymorphism (다형성)
그럼 이제 하나하나 자세히 알아보자!
- 데이터와 기능을 하나의 단위로 묶는 것
- 은닉(hiding): 구현은 숨기고, 동작은 노출시킴
- 느슨한 결합(Loose Coupling)에 유리: 언제든 구현을 수정할 수 있음
흠... 그럼 느슨한 결합은 뭐지...?
느슨한 결합
코드 실행 순서에 따라 절차적으로 코드를 작성하는 것이 아니라, 코드가 상징하는 실제 모습과 닮게 코드를 모아 결합하는 것을 의미한다.
마우스 구동을 위한 코드 작성을 예로 들자면 스위치가 눌리고, 전기 신호가 생겨서, 전선을 타고 흐르고.. 와 같은 전 과정을 이곳저곳에 나누어 작성하는 것이 아니라, 마우스의 상태를 속성(property)으로 정하고 클릭, 이동을 메서드(method)로 정해서 코드만 보고도 인스턴스 객체의 기능을 상상할 수 있게 작성하는 것
그럼 은닉화는?
은닉화
- 내부 데이터나 내부 구현이 외부로 노출되지 않도록 만드는 것이다.
- 디테일한 구현이나 데이터는 숨기고, 객체 외부에서 필요한 동작(메서드)만 노출시켜야 한다.
은닉화의 특징을 살려서 코드를 작성하면 객체 내 메서드의 구현만 수정하고, 노출된 메서드를 사용하는 코드 흐름은 바뀌지 않도록 만들 수 있다.
반면 절차적 코드의 경우 데이터의 형태가 바뀔 때에 코드의 흐름에 큰 영향을 미치게 되어 유지 보수가 어려움.
그래서 더 엄격한 클래스는 속성의 직접적인 접근을 막고, 설정하는 함수(setter), 불러오는 함수(getter)를 철저하게 나누기도 한다.
추상화
- 내부 구현은 아주 복잡한데, 실제로 노출되는 부분은 단순하게 만든다는 개념이다.
- 추상화를 통해 인터페이스가 단순해진다
- 너무 많은 기능들이 노출되지 않은 덕분에 예기치 못한 사용상의 변화가 일어나지 않도록 만들 수 있다
전화로 예를 들어보자...
전화라는 객체가 있다면, 그 안에는 스피커와 마이크가 존재하고, 서킷 보드 등이 존재하는 등 내부 구현이 되어 있을 것이다. 그러나 실제로 우리가 사용할 때에는, 이러한 존재에 대해서는 생각하지 않고 단순히 수화기를 들고 버튼을 눌러서 해결하는 것으로 인터페이스(interface)를 단순화할 수 있다.
추상화는 캡슐화와 비교해서 종종 헷갈려 하는 개념 중 하나이다.
캡슐화가 코드나 데이터의 은닉에 포커스가 맞춰져있다면, 추상화는 클래스를 사용하는 사람이 필요하지 않은 메서드 등을 노출시키지 않고, 단순한 이름으로 정의하는 것에 포커스가 맞춰져 있다.
클래스 정의 시, 메서드와 속성만 정의한 것을 인터페이스라고 부른다. 이것이 추상화의 본질!
상속
- 상속은 부모 클래스의 특징을 자식 클래스가 물려받는 것이다.
- 부모/자식으로 이야기하기도 하지만, 보다 그 특징을 자세하게 설명하는 용어는 "기본 클래스(base class)의 특징을 파생 클래스(derived class)가 상속받는다"로 표현하는 것이 적합
사람이라는 클래스가 있다고 가정해보자!
사람은 기본적으로 이름과 성별, 나이와 같은 속성, 그리고 먹다, 자다 등과 같은 메서드가 있다고 볼 수 있음.
거기다 추가적으로 학생(Student)이라는 클래스를 작성한다고 생각해 보자. 그런데 이때 앞서 구현했던 사람(Human) 클래스의 속성과 메서드를 다시 구현한다면 비효율적일 것이다. 학생의 본질은 결국 사람이므로, 상속을 이용하여 학생(Student) 클래스는 사람(Human) 클래스를 상속받을 수 있다. 학생은 추가적으로 학습 내용, 공부하다 와 같은 속성/메서드를 추가한다.
다형성
- Polymorphism이라는 단어의 poly는 "많은", 그리고 morph는 "형태"라는 뜻
- 즉 "다양한 형태"를 가질 수 있다는 말
"말하다"라는 동작의 본질은 "입으로 소리를 내다"를 의미한다. 그러나, 각기 다른 동물들이 "말할 때" 제각각의 소리를 내는 것처럼, 객체 역시 똑같은 메서드라 하더라도, 다른 방식으로 구현될 수 있다.
흠... 좀 어려운데...? 적절한 예 없을까?
그럼 HTML 엘리먼트를 예로 들어보자!
이것이 바로 다형성!
만약 다형성이 없다면...?
이제 마지막으로 주요 개념과 의미에 대해 다시 정리해보자!
- 캡슐화는 코드가 복잡하지 않게 만들고, 재사용성을 높인다.
- 추상화는 마찬가지로 코드가 복잡하지 않게 만들고, 단순화된 사용으로 변화에 대한 영향을 최소화한다.
- 상속 역시 불필요한 코드를 줄여 재사용성을 높인다.
- 다형성으로 인해 동일한 메서드에 대해 if/else if와 같은 조건문 대신 객체의 특성에 맞게 달리 작성하는 것이 가능해진다.
객체지향 프로그래밍은 사람이 세계를 보고 이해하는 방법을 흉내낸 방법론이라고 생각하면 된다.
코드 상에서, 혹은 화면에 보이는 하나의 요소를 객체 단위로 구분시켜서 생각하면, 보다 이해하기 쉬운 코드를 작성할 수 있게 된다. OOP의 특성을 이해하고 잘 사용하면 좋은 설계를 할 수 있다!