OOP

OOP

내가 개발공부를 시작할 수 있도록 도와준 python 이나, 곧 함께하게 될 JavaScript 는 모두 객체 지향 프로그래밍 언어 이다.

다만 약간의 차이가 있다. JS 는 프로토 기반의 객체 지향 언어로, class 개념이 존재하지 않는다. 객체를 생성할 때에는 객체 리터럴, object 생성자 함수, 생성자 함수 등을 통하여 생성한다. 또, 프로토 타입을 통해 직접 객체를 연결할 수도 있다. 반면에 python 은 class 기반의 언어로, class 를 통하여 객체의 자료구조와 기능을 정의하고 인스턴스를 생성한다.

(ref: poiemaweb)

여태까지 나는 두 언어를 사용하면서 해당 개념에 대해 흐릿하게나마 이해하였지만, 그래서 객체 지향이 뭔데? 라고 물어보면 명확한 정의와 예시를 들어 대답을 하기 어려웠다.

객체 지향 프로그래밍이 정확하게 무엇일까?

What is OOP?

객체 지향 프로그래밍(Object-Oriented Programming) 은 프로그래밍에서 필요한 데이터를 추상화 시켜 객체를 만들고, 그 객체들 간의 조합 및 유기적인 상호작용을 통해 logic 을 구성하는 프로그래밍 방법을 의미한다.

앞서 공부했던 clean architecture, DDD patterns 에 대한 접근은 어떤 system architecture 가 좋은 구조일까? 에 대한 질문의 대답들이었다면, OOP 는 프로그램을 어떻게 설계할것인가? 에 대한 대답 중 하나이다.

OOP 의 구성 요소들은 위 사진처럼 class, object, 추상화 abstraction, 상속 inheritance, 캡슐화 encapsulation, 다형성 polymorphism 으로 이루어져있다.

먼저 class 라는 개념부터 짚어보자.

class 와 object

class 란 문제 해결을 위해 필요한 데이터를 추상화하여 행위, 상태를 정의한 것을 의미한다. 그리고 object 는 class 에서 정의한 것을 토대로 생성된 인스턴스이다. 그렇다면 추상화는 또 무엇일까?

클래스와 객체의 관계에 대해 찾아보니, 보통 붕어빵(=객체)/붕어빵(=클래스) 틀에 빗대어 비유하곤 한다. 다만 내가 첨언하고 싶은건 class 는 실재하지 않는 개념이므로 붕어빵 틀을 틀이라는 실재하는 존재라고 받아들이기 보다는 class 는 object 를 위한 도구라고 받아들여야 해당 개념을 이해하기 쉽다는 점이다. 좋은 예가 있는 tech-blog 를 찾아 링크를 아래에 첨부한다.

(참고하면 좋은 블로그 : evans library)

추상화와 상속

컴퓨터적인 용어로 추상화(abstraction) 는 복잡한 자료, 모듈, 시스템 등으로부터 핵심적인 개념 또는 기능을 간추려 내 단순화하는 것을 의미한다. 칸딘스키나 피카소의 그림을 떠올리면 이해하기가 쉽다.

위의 그림은 피카소가 그린 소(bull series) 이다. 왼쪽의 '소' 에서 오른쪽의 '선' 으로 가는 행위가 바로 추상화이다. 오른쪽으로 갈수록 상위의 개념이라는 뜻이다.

하위개념인 '소' 는 '선' 이 가진 특징들을 가지고 있지만, 상위개념인 '선' 은 '소' 의 속성들을 가지고 있지 않는다. 이렇듯 하위개념이 상위개념의 속성을 그대로 물려받는 것을 상속(inheritance) 이라고 한다. 확장(extends) 도 상속과 같은 개념이다. 하위 개념의 입장에서 보면 상위의 속성을 상속 받는 것이지만, 상위 개념 입장에서 보면 자신의 속성들이 하위 개념으로 넘어가면서 확장되는 것이기 때문이다.

상속은 캡슐화를 유지하고 클래스의 재사용이 용이하도록 해준다. 그렇다면 캡슐화는 무엇일까?

캡슐화

캡슐화(encapsulation) 는 특정 문제를 해결하기 위한 기능과 특성을 '클래스'라는 '캡슐'에 넣어, 클래스 내부를 감추는 기법이다. 클래스를 캡슐화 함으로써 클래스를 사용하는 쪽에서는 해당 클래스의 내부 로직을 파악할 필요가 없어지고, 클래스 내에서 사용되는 변수나 메소드를 감출 수 있기 때문에 필요 이상의 변수나 메소드가 클래스 외부로 노출되는 것을 막아 보안도 챙길 수 있다.

이렇게 클래스 내부의 데이터를 감추는 것을 정보 은닉(Information Hiding) 이라고 하며, 보통 public, private, protected 같은 접근제한자를 사용하여 원하는 정보를 감추거나 노출시킬 수 있다.

public 은 클래스 외부에서도 마음대로 접근할 수 있도록 만들어준다. private 를 사용하여 선언된 변수나 method 는 클래스 내부에서만 사용될 수 있고, 외부로는 아예 노출되지 않는다. protected 의 경우는 해당 클래스를 상속받은 클래스와 같은 패키지안에 있으면 사용이 가능하다.

다형성

다형성은 하나의 변수나 method 를 이용해 다양한 결과를 만드는 것을 의미한다. 캡슐화와 마찬가지로 nest.js 에서 배웠던 interface 라는 정의를 생각하면 이해하기 편하다. 상속도 어떻게 보면 다형성의 예가 될 수 있겠다.

오버라이딩 over-riding

오버라이딩은 super 클래스의 method 와 같은 이름, 매개변수를 재정의하여 부모클래스의 속성을 덮어쓰게 하는 것을 의미한다.

오버로딩 over-loading

오버로딩은 같은 이름의 함수를 여러 개 정의하고, 매개변수의 타입과 개수를 다르게하여 각각 다르게 호출하는 것을 의미한다.

Why OOP?

이제 우리는 OOP 가 무엇인지 알았다. 그렇다면 왜 OOP 를 사용해야 할까? OOP 를 따라 프로그램을 설계하는 것에 어떤 장점이 있을까?

프로그래밍 방식은 절차적 프로그래밍 방식에서 구조적 프로그래밍 방식으로, 그리고 구조적 프로그래밍 방식에서 객체 지향 프로그래밍 방식으로 진화해왔다.

절차적 프로그래밍 방식 procedural programming 을 간단하게 설명하자면 루틴, 프로시저 등의 개념을 통해 함수를 위에서 아래로 순차적으로 실행하는 것을 의미한다. 절차적 프로그래밍은 정해진 순서대로 입력을 해야 하므로 순서가 바뀌면 결과값을 도출하기 어렵다. 마찬가지의 이유로 유지보수 또한 쉽지 않다.

이러한 단점을 극복하기 위한 하위 개념으로 구조적 프로그래밍이 등장했다. 구조적 프로그래밍의 대표적인 예로는 C언어가 있다. 구조적 프로그래밍은 프로그램을 작성할 때 알고리즘을 세분화하여 계층적인 구조가 되도록 설계하는, 하향식(Top-Down) 을 이용한 프로그래밍 기법으로, 순차-선택(if)-반복(while, for) 등의 제한적인 몇 가지 방법만을 이용하여 그와 유사한 서브 프로그램들로 프로그램을 구성한다. 이러한 특성을 이용하여 절차적 프로그래밍보다 코드의 재사용성을 높이고, 프로그램의 흐름을 간략화하는데에 성공하였으나 data와 프로그램 실행 절차를 분리하다보니 data 관리에 소홀해져 엉뚱한 데이터가 엉뚱한 함수에 전달되는 등의 문제가 발생하였다.

구조적 프로그래밍의 단점을 극복하기 위해 등장한것이 바로 객체 지향 프로그래밍, OOP 이다. OOP 는 구조적 프로그래밍과 반대로 객체들을 만들고 이 객체들을 조합하여 문제를 해결하는 상향식(Bottom-Up) 을 이용한 프로그래밍 기법이다. OOP 를 사용하면 코드의 재사용성이 높아지고, 유지보수가 쉬워져 업무 분담이 쉽고 개발기간 및 비용을 절감할 수 있다.

SOLID

OOP 에는 다섯가지 기본 원칙이 있다. 이를 SOLID 원칙이라고 한다.

ref) devscope / SOLID Principles

SRP

Single Responsability Principle(단일 책임 원칙). 하나의 클래스는 하나의 책임만 가져야 한다. 즉, 같은 목적을 가진 클래스는 묶되 다른 목적을 가진 클래스들은 분리해야 한다는 것이다.

OCP

Open/Close Principle(개방/폐쇄 원칙). 확장에는 열려있으나 변경에는 닫혀있어야 한다.

LSP

Liskov Substitution Principle(리스코프 치환 원칙). 프로그램의 객체는 프로그램의 정확성을 깨뜨리지 않으면서 하위타입의 인스턴스로 바꿀 수 있어야 한다.

ISP

Interface Segregation Principle(인터페이스 분리 원칙). 특정 클라이언트를 위한 인터페이스 여러개가 범용적으로 사용되는 인터페이스 하나보다 낫다.

DIP

Dependency Inversion Principle(의존 관계 역전 원칙). 추상화에 의존하되, 구체화에 의존해서는 안된다. 상위 모듈은 하위 모듈의 구현 내용에 의존해서는 안된다.

공유하기 글 요소 저작자표시

from http://csue.tistory.com/28 by ccl(A) rewrite - 2021-04-27 21:25:44

댓글