OOP - 객체지향프로그래밍

단델리옹·2021년 4월 9일
0
post-thumbnail
글에 사용된 모든 reference는 글의 마지막에 적어놨습니다. 
혹시라도 제가 놓친 부분이 있다면 알려주시면 추가/수정 하겠습니다.
혹시 문법 틀린부분 있으면 알려주시면 고치겠습니다.

𝟘. Programming Paradigm

프로그래밍 패러다임이란 프로그래밍하는 스타일이라고 생각하면 이해하기 쉽다.
이 패러다임은 두 종류로 나뉘어진다.

  • Imperative(명령형)
    알고리즘을 명시하고 목표는 명시하지 않음
    => 무엇과 같은지 가 아니라 뭘 해아하는지
  • Declarative(선언형)
    목표를 명시하고 알고리즘을 명시하지 않음
    => 뭘 해야할지 가 아니라 무엇과 같은지

이 중 오늘 다뤄볼 Object Oriented Programming (OOP)는 Imperative 에 속한다.

❶. Definition

Object / 객체
사람이 감각하거나 인식하거나 행동하는 것의 대상이 되는 사물 [출처]한국어기초사전

객체 지향 프로그래밍
데이터를 하나의 사물/물체와 같이 취급한다. 현실 세계의 개념들을 프로그래밍으로 옮겨온다고 생각하면 쉽다.

현실 세계의 사물, 전화기가 있다. 다이얼을 누른다, 상대방의 소리가 들린다, 소리를 전달할 수 있다, 전화벨이 울린다 등 전화기의 특성, 기능등을 프로그래밍 하는 기법이 객체 지향 프로그래밍이다.

장점이라고 한다면 코드의 재사용이 쉽고 변형 가능성이 높다.

객체 전화기 코드를 기반으로 스마트폰, 폴더폰, 삼성폰 애플폰 등 공동적으로 적용되는 코드를 재사용 할 수 있다.

❷. 요소들

encapsulation(캡슐화), inheritance(상속), abstraction(추상화), polymorphism(다형성)

2-1. Encapsulation

객체 지향 프로그래밍은 속성과 기능들을 객체 속에 저장한다.

Drop down box를 빗대어 표현하면 이해가 쉬울까? drop down menu는 그것을 누르기 전까지는 정확히 어떤 내용이 들어있는지 알 수 없다. 하지만 카테고리의 이름을 보고 유추 할 수 있다. 객체도 비슷하다.

속성과 기능들을 겉에서 볼 수 없고 감싸 놓은 것, 그것을 캡슐화라고 부른다. 캡슐화 함으로서 변경되 면 안 되는 예민한 정보들 (closure 함수 안에 저장된 변수 같이) 외부에서 변경할 수 없도록 은닉화 시킨다.

2-2. Inheritance

(상속)

객체는 Class라는 데이터모델을 이용하여 작성하게 되는데 이 클래스의 속성과 기능들을 그대로 가져와 사용하고 싶을 때 다른 클래스가 이 속성, 기능들을 상속받는다.

위에서 예시로 들었던 전화기와 같다. 전화기라는 큰 카테고리 밑에 터치폰, 폴더폰, 슬라이드폰, 집전화기 등 여러 카테고리로 다시 나뉘어진다. 이 때, 하위 카테고리가 전화기라는 기본적인 공통 특성들을 그대로 가져와 사용한다.

상위 클래스를 부모, 하위 클래스를 자식이라고 한다.

2-3. Polymorphism

(다형성)

같지만 다르다. 부모와 자식 클래스를 보면 이해가 쉬울것이다.

자식 클래스는 부모 클래스의 속성과 기능들을 상속받는다. 상속받은 것들을 Overwrite, 즉, 중복하여 덮어쓸 수 있다.

전화기가 있다. 다이얼을 누르는 방식이 버튼으로 지정되어있다. 하지만 하위 카테고리인 스마트폰으로 가면 다이얼을 누르는 방식이 버튼에서 터치로 변경이 가능하다. 다이얼을 누른다라는 같은 기능이지만 상위 카테고리인 전화기의 버튼이 하위 카테고리인 스마트폰의 터치로 변경되었다.

위와 같이 같은 기능이라도 구현되는 방식이 다를 수 있다.

키보드 위의 자판들은 다 똑같이 생겼지만 각 자판이 다른 역할을 하는 것 처럼 하나의 메소드나 클래스가 다양한 방법으로 동작할 수 있다.

2-4. Abstraction

추상화
=> 구체적인 것을 분해해서 관심 영역에 대한 특성만을 가지고 재조합하는 것
OOP 추상화
=> 추상화란 구체적인 것을 분해해서 관심 영역(어플리케이션 경계, Application Boundary)에 있는 특성만을 가지고 재조합하는 것 = 모델링 [출처]여름나라겨울이야기

❸. Object & Class & Prototype

놀랍게도 이 세개는 같은 듯 다르다.

3-1. Object & Class

객체는 사물이다. 온라인 쇼핑몰에서 판매하는 각각의 물건들을 생각하면 쉬울 것 같다.
클래스는 카테고리다. 물건들이 카테고리별로 나뉘어져 있는 것을 생각하면 쉬울 것 같다.

쥐와 고양이는 각각 클래스다. 하지만 톰과 제리는 각각 객체이다.

3-2. Then What is Prototype?

Prototype-based programming은 OOP의 스타일 중 하나이다. 프로토타입은 클래스와 비슷하지만 다른 녀석이다. 클래스는 상속이라면 프로토타입은 복제이다. 객체를 복제함으로써 그 객체의 동작 방식등을 재사용하는것이다. 대표적인 예시로 Array가 있다.

JavaScript에서 typeof Array를 하면 결과값은 Object가 나온다.

(어머나 세상에나)

우리는 Array라는 객체를 계속 복제하여 재사용 하고 있던 것이다.
(복제라고만 하기엔 살짝 헷갈릴 수 있다. 일단은 비슷한 것 이라고만...)

클래스와 다른점이라면 클래스는 하나의 인스턴스를 만들어서 특성들을 중복적으로 재사용하는것이다.

쥐의 이름은 제리, 털의 색은 갈색 이라고 하는 등 이름과 털 그리고 팔 다리의 개수 등 특성을 기반으로 새로운 객체를 만드는 것. 하지만 프로토타입 기반의 경우, 제리라는 객체를 만들고 여러 제리들을 반복적으로 복제하여 사용하는 것이다.

다른 예시로, 클래스가 애플이라면, 애플의 로고, 형태는 노트북인가? 의 형식이라면 프로토타입은 하나의 설계도를 가지고 공장에서 맥북 2015 프로 레티나 모델을 여러개 찍어내어 사용하는 것.


polishing 필요


❹. Prototype-based programming

4-1. Prototype chain


[그림1]

위의 그림은 prototype을 보여준다. Object()는 복사본이 아닌 원본, 즉 위에서 공장 설계도 애플 예시를 들었는데 거기서 설계도 라고 생각하면 좋겠다. 설계도를 이용하여 복제품을 만들고 그 복제품이 곧 car가 된다.

근데 혹시 아는가? 신제품이 있을 때, 우리는 설계도만 보관하지 않고 시제품 또한 갖고 있다. 설계도만 저장했을 때 오해로 인한 기대와는 다른 아웃풋이 생길 수 있기 때문이다. 이러한 시제품같은 중간 역할을 하는 것이 위의 그림 중 built-in 이다.

실제로 코드를 돌려보면,Object 만 쳤을 시에는 Object의 코드들, constructor 역할을 하는 코드들이 리턴된다. 반면에 Object.prototype을 입력하게 되면 객체 형식으로 보여준다.
이것은 하위 객체 car에서 .__proto__ 한 것과 같은 결과값이 나온다.


[그림2]

모든 prototype들의 맨 위에는 Object가 있다. 자바스크립트에서 Array 등, prototype 기반인 것들을 사용하다보면 toString 등 정의되지 않은 메소드들을 찾아볼 수 있는데 그것들은 모두 Object 안에 정의되어있다.

그림2를 보면서 눈치챘겠지만 .prototype은 하위 객체를 가리키고 __proto__ 는 상위 객체를 가리킨다.

4-2. Class 와 Prototype

실은 이 블로그를 적으며 매우 헷갈렸던 부분이다. prototype을 공부하려고 하니 class와 같다고 생각하는데 새로운 개념들이 계속 출몰했기 때문이다.

결론적으로 이는 JavaScript라는 언어가 객체지향언어로 개발된 언어가 아니라서 일어난 일 이었다.

class와 super라는 개념이 JavaScript에서도 사용 가능하다라는 걸 알았을 때, 그 순간만큼 머릿속이 빠르게 정리되는 경험도 없었을 것 이다.

위에서 잠시 설명했던 부모 클래스와 자식 클래스, 그것이 .prototype과 __proto__인 것 이다. (가 아니라 비슷한 것이다!!!)(결국 둘 모두 상위객체와 하위객체를 가리키고 있으므로)

4-3. New & Constructor

new 라는 키워드가 있다. 이것은 새로운 객체를 선언할 때 사용된다.

let arr = new Array();
let obj = new Object();

위와 같은 방식으로 사용된다.

아까부터 계속 나온 constructor는 이때 사용되는 녀석이다.

혹시 이 글의 처음에 톰과 제리를 이야기 하던것을 기억하는가? 쥐와 고양이 이지만 이름과 털의 색 등등 하나의 객체가 된 고양이와 쥐. 톰과 제리이다.

객체와 클래스의 큰 차이점이 고양이과 쥐, 톰과 제리였다. 여기서 알 수 있는 부분은 객체들은 그들만의 특별한 무언가가 주어진다는 것이다. 이 떼 그 특별한 무언가를 설정할 수 있도록 도와주는것이 constructor이다.

Constructor는 새로운 객체가 선언될 때 초기값을 설정하는 역할을 한다. 이 초기값은 closure 함수 내에 저장되어있는 변수들을 떠올리면 이해하기 쉬울거다.

계속 예시를 들었던 톰과 제리, 이것을 새로운 객체로 선언할 때 이름을 넘겨준다던지 등의 초기값을 선언하게 되는것이다.

// class Cat 이 있다고 가정하겠다.
constructor(name) {
	this.name = name;
}

// class 의 constructor가 위와 같을 때, 
let tom = new Cat('Tom');
// 위와 같은 형식으로 이름이 Tom인 고양이를 tom이라는 변수에 담아줄 수 있다.

이것이 클래스라면 프로토 타입은 클로져 함수 안에 선언 및 할당 되는 변수들이라고 생각하면 편할 것 같다.

const Cat = function(name) { // 이 함수가 constructor와 같은 역할을 한다.
  this.name = name;
};

Cat.prototype.getName = function(){ // 클래스의 메소드와 같은 역할을 한다
  return this.name;
}

let tom = new Cat('tom'); // 프로토타입으로 가져와봤다.

4-4. super

키워드 super는 하위 객체에서 상위 객체의 constructor등을 불러올 때 사용된다.

예를들어 Animal 이라는 클래스 밑에 Cat이라는 클래스가 있다고 가정하겠다. 그렇다면 Cat 클래스를 정의할 때, 우리는 extends Animal을 적어주어야 할 것이다. (단순이 Animal 기반의 하위 클래스를 만들겠다는 의미이다.)

class Cat extends Animal{
	constructor(name){
    	super(); //Animal의 cosntructor를 불러온다. 
      // 만약 Animal의 constructor가 인자를 필요로 안다면,
      // Parameter 값을 넣어줘야 한다면 넣어준다.
      // 클래스 Animal 안의 메소드 등을 사용 가능하다.
      // Cat은 Animal 기반으로 만들어진 하위, 자식 클래스이다.
      	this.name = name;
    }
}

프로토타입은 위와 같으 쉽고 단순하게 할 수 없다.
call 혹은 apply 함수등을 사용하여 this를 넘겨주어야 한다.
확실히 이해하기 위해선 bind, call, apply, this의 개념 정리가 불가피하다.

const Cat = function(name){
  Animal.call(this);
  this.name = name;
};
            
Cat.prototype = Object.create( Animal.prototype );
profile
민들레씨 날아가듯 내 멘탈이 날아갈 때...

0개의 댓글