Basic OOP

유웅조·2020년 2월 25일
0

Basic

목록 보기
5/13

객체 지향의 등장

초기 프로그래밍 방식은 절차적 프로그래밍 방식이었다. 어떠한 논리를 알맞은 논리 순서대로 써내려가는 것이다. 이러한 경우, 코드의 덩치가 커질수록 복잡해지고 유지보수가 어려워진다.

이후 프로그램을 함수 단위로 나누고 호출을 하는 구조적 프로그래밍 방식이 등장하면서 앞선 문제는 일정 부분 해소되는 듯 했다.

하지만 함수를 통해 데이터의 처리 방법은 구조화했지만 데이터 자체는 구조화하지 못했고, 실행 콘텍스트를 저장할 방법도 없었다. 그래서 프로그래머는 가능한 모든 변수를 다 조사해야 하는 불가능한 어려움에 봉착했다.

이를 극복하기 위한 대안으로 객체 지향 프로그래밍이 등장했다. 작은 문제들의 독립성/신뢰성을 보장해 이들을 조합해 큰 문제를 해결하는 방식인 상향식(BOTTOM-UP) 해결법을 도입했다.

현대에 이르러 객체 지향 프로그래밍도 매우 복잡해지면서 이를 간결하게 정리할 필요성이 생겼고, 디자인 패턴(프로그래밍 형식을 정하는 일종의 약속)이라는 것이 등장했다.

객체 지향 5원칙 "SOLID"

  • Single Responsibility Principle | 단일 책임 원칙 : 객체는 오직 하나의 책임을 가진다. 예를 들어, 계산 기능을 갖고 있는 클래스가 있다고 했을 때 나중에 이 함수를 수정할 일이 있더라도 무조건 계산과 관련된 문제만 다루어야 한다.
  • Open-Closed Principle | 개방-패쇄 원칙 : 객체 기능의 확장에 대해서는 개방적, 수정에 대해서는 폐쇄적이어야 한다.
  • Liskov Substitution Principle | 리스코프 치환 원칙 : 부모 클래스가 들어갈 자리에 자식 클래스를 넣어도 계획대로 잘 작동해야 한다. 상위 클래스는 하위 클래스에서 추상화해야하는 기능만을 가지고 있어야 한다.
  • Interface Segregation Principle | 인터페이스 분리 원칙: 일종의 인터페이스의 SRP. 인터페이스를 책임 단위로 작게 나누는 것을 말한다.
  • Dependency Inversion Principle | 의존성 역전 원칙 : 고수준의 클래스는 저수준의 클래스에 의존해서는 안된다. 고수준의 클래스는 저수준 클래스를 추상화한 인터페이스만을 바라보기 때문에 이 인터페이스는 고수준을 변경하지 않고도 교체될 수 있다.

디자인 패턴

  • 일반적인 디자인 패턴

    1. Factory : 객체를 만들어 반환하는 함수를 (생성자 대신) 제공하여 초기화 과정을 외부에서 보지 못하게 숨기고 반환 타입을 제어하는 방법.
    2. Builder : 인스턴스를 생성자를 통해 직접 생성하지 않고, 빌더라는 내부 클래스를 통해 간접적으로 생성하게 하는 패턴.
    3. Singleton : 특정 클래스의 객체를 한개만 유지하는 패턴.
    4. Facade : 복잡한 호출과정을 대신 처리해주는 wrapper 객체를 따로 만들어 시스템의 복잡성을 감추고, 해당 시스템에 접근할 수 있는 인터페이스만을 제공한다.
  • 자바스크립트에서 자주 활용될 수 있는 패턴

    1. Module | 모듈 패턴 : 소스 코드를 모듈 단위로 관리한다. 전역 변수, 함수의 활용을 최소화해서 소스 코드끼리의 충돌을 방지한다. 각 모듈 간의 의존성을 최소화하거나 의존성 파악을 용이하게 한다.
    2. Memoization | 메모이제이션 페턴 : 자바스크립트의 객체는 쉽게 새로운 속성을 추가하고 수정할 수 있다. 따라서 캐시와 같은 기능을 수행하기에 용이하며, 복잡한 연산이 반복적으로 일어날 때 성능 최적화에 유용하다.
    3. Call Back | 콜백 패턴 : 변수나 인자로 함수를 쉽게 설정하고 전달할 수 있기 때문에 비동기 처리가 끝난 뒤 해당 함수를 호출할 수 있도록 다양하게 응용할 수 있다.
    4. Currying | 커링 패턴 : 하나의 공용 함수가 있는 경우, 이를 세부적인 기능을 하는 함수로 나누고 싶을 때 유용하다.

클래스와 객체

상속화(Encapsulation): 변수와 함수를 하나로 묶는 것을 데이터를 데이터의 번들링이라고 하는데, 객체 지향에서 이 번들링을 클래스를 통해 구현한다. 해당 클래스의 인스턴스 생성을 통해서 클래스 안에 포함된 변수와 메소드에 접근한다.
정보 은닉(Informatino Hiding): 클래스는 외부에서는 노출 가능한 메소드에만 접근 가능하기 때문에 클래스 내부를 알 수 없도록 설계된다. 따라서 정보를 제한적으로 제공하고 클래스끼리의 결합도를 낮춘다. (일반적인 접근 제한: public: 클래스의 외부에서 사용 가능, protected: 상속 받은 자식 클래스에 노출, private: 해당 클래스의 내부에서만 사용 가능, Python은 해당 기능을 사용하지 않는다)

Inheritance: 자식 클래스는 부모 클래스의 특성과 기능을 물려받을 수 있다. 이것을 상속(Ingeritance)라고 한다. 자식 클래스는 상속받은 기능을 수정해서 사용할 수 있다.

다형성(Polymorphism): 하나의 변수, 또는 함수가 상황에 따라 다른 의미로 해석될 수 있는 것을 말한다. 상위 클래스와 그것을 상속받는 다수의 하위 클래스가 있다고 가정할 경우, 하위 클래스에서 다양한 방식으로 변형, 수정 가능시켜 다른 형태로 만들 수 있다.

멤버 변수 | 멤버 함수: 기본적으로 클래스 내부에 있는 어떤 항목들을 가리킬 때, 멤버라는 말을 사용한다. 따라서 멤버 변수란 클래스 내에서 사용하는 변수를 말한다. 그리고 멤버 함수란 이러한 변수를 처리하는 함수들을 가리킨다.

클래스, 객체, 인스턴스: 클래스란 객체를 만들어 내기 위한 설계도, 그리고 연관되어 있는 변수와 메소드의 집합이다. 객체란 클래스대로 생성된 실체, 구현될 대상(OBJECT)를 말한다. 인스턴스랑 실제 메모리에 할당된 객체를 말한다.

자바스크립트에서 클래스를 만드는 방법

자바스크립트는 객체 지향 프로그래밍 언어에서 기본적으로 제공하는 클래스를 지원하지 않는다. 대신 프로토타입이라는 것을 이용해 OOP를 지원한다. ECMA6에는 Class 문법이 추가되어 Class를 사용할 수 있지만, 그렇다고 자바스크립트가 Prototype => Class로 바뀌었다는 것을 의미하지는 않는다.

자바스크립트에서 클래스 대신 function과 new 키워드를 사용해 클래스를 표현할 수 있다. 하지만 이렇게 할 경우, 인스턴스를 생성할 때마다 중복된 멤버 변수가 계속 메모리에 할당될 수 밖에 없다. 이럴 때 Prototype을 사용하면 된다.

자바스크립트의 Prototype에는 Prototype Link와 Prototype Object라는 것이 존재한다. Prototype Object는 함수를 정의하고 생성할 때, 함께 생성된다. 그리고 해당 함수의 prototype이라는 속성을 통해 Prototype Object에 접근할 수 있다.

Prototype Object는 기본 속성으로 constructor__proto__를 가지고 있다. 여기서 constructor는 해당 함수를 가리키고, __proto__는 Prototype Link이다.

__proto__는 모든 객체가 가지고 있는 속성인데, 이는 부모 함수의 Prototype Object를 가리킨다. 특정 객체의 속성을 조회할 때, 만약 특정 객체가 그 속성을 갖고 있지 않을 경우 해당 속성을 찾기 위해 proto가 가리키고 있는 부모 함수의 Prototype Object를 조회한다. 해당 속성을 찾을 때까지 타고 올라가며 최종적으로 Object의 Prototype Object까지 조회한다. 이와 같은 형태를 Prototype Chain이라고 한다.

Prototype은 여러 객체가 하나의 객체를 공유하고 있기 때문에 메모리를 하나만 사용한다. 따라서 객체를 여러개 생성해야 할 때는 Prototype을 사용하는 것이 효율적이다. 그리고 Prototype의 속성만 수정함으로써 모든 객체를 재설정할 수도 있다.

그러나 Prototype Chain이 깊어질 수록 검색하는 속성 탐색 시간이 늘어난다. 따라서 특정 객체에서 자주 참조해야 하는 속성이라면 Prototype이 아니라 객체 자체의 속성으로 만드는 것이 효율적일 것이다.

클래스 기반에서는 상속을 사용한다. 하지만 프로토타입 기반에서는 객체를 원형으로 하여 복제를 하고, 이를 이용해 객체의 동작 방식에 접근할 수 있다. 이와 같은 행위를 "위임"이라 하며, "위임"을 통해 상속의 과정을 대체한다고 볼 수 있다.

클래스를 사용하게 되면 객체의 만듦새와 기능을 정의하게 된다. 그러면서 클래스에서 생성된 인스턴스는 클래스에서 정의된 타입에 맞추어 주어진 방식대로 동작할 수 밖에 없는 일종의 안정성과 예측성이 보장된다.

프로토타입 기반의 객체는 프로토타입을 참조하는 것이기 때문에 프로토타입과 자식 객체가 메모리 혹은 구조적 유사성을 가질 필요가 없다.

클래스 설계, 클래스 상속의 장점과 단점

클래스를 상속해서 설계하게 되면 상위 클래스에서 필드 및 공통 메소드를 상속해서 사용할 수 있기 때문에 소스 코드의 양이 줄어들고 기능을 확장하기 용이하다. 그러나 상속 구조가 복잡해지면 상위 클래스에서 어떤 변화가 생겼을 때, 하위 클래스에 어떤 영향을 주는지 예측하기 힘들어질 수도 있고 예상과 다르게 작동할 수도 있다.

더 좋은 코드란?

좋은 코드에 대한 재미있는 농담이 있다.

The Only Valid Measurement of Code Quality: WTFs / Minute

우스게 소리이지만 한편 일리 있다고도 생각한다. 좋은 코드란 읽기 쉽고, 재사용 가능하며, 리팩토링 가능하도록 작성하는 것이라고 생각한다.

아래는 클린코드 자바스크립트 버전에 대한 간략한 소개이다. 자세한 것은 클린코드 참조

변수
가능하면 의도가 명확하고, 검색 가능하도록 변수명 짓기

함수
가능하면 너무 많은 3개 이상의 인자는 피하기

1개의 함수는 1개의 기능만 하기

함수명은 직관적으로 짓기

중복된 코드 피하기

Object.assign을 사용하기

매개변수로 플래그 사용하지 않기

사이드 이펙트 피하기

명령형 프로그래밍이 아닌, 함수형 프로그래밍 지향하기

조건문 캡슐화 하기

죽은 코드 지우기

클래스
상속보다는 조합을 사용하기

SOLID 원칙 지키기

등등...

0개의 댓글