본문 바로가기
Front-End/자바스크립트 (JavaScript)

[자바스크립트] 객체 지향 프로그래밍(OOP): 클래스와 인스턴스

by MS_developer 2022. 9. 21.

 

 

 

개발을 하다보니 개인 프로젝트임에도 규모가 점점 커져가는 것이 느껴진다. 자연스럽게 '팀 프로젝트는 함께 작업하는 파일과 폴더가 얼마나 많을까'라는 의문과 함께 한 가지 생각이 들었다.

 

"어떻게 해야 같은 개발자가 봤을 때 이해하기 쉽고 효율적이면서 합리적인 구조를 갖춘 코드를 구성할 수 있을까?"

 

아마 다양한 프로그래밍 지식을 활용할 줄 알아야 할 것이다. 그리고 질문에 대한 해답을 구하고자 할 때, 흔히 볼 수 있는 단어가 있다. 바로 객체 지향 프로그래밍Object Oriented Programming이다.


객체 지향 프로그래밍(OOP)이란?

객체 지향 프로그래밍이란 컴퓨터 프로그래밍 패러다임의 하나로 소프트웨어 디자인에 있어 컴퓨터 프로그램을 "객체Object"들의 모임으로 파악하고자 하는 것이다. 즉, 컴퓨터 프로그램을 명령어 한 줄 한 줄 순차적으로 보는 것이 아니라 프로그램을 각각의 속성과 기능을 가진 여러 개의 '부품들(객체)'로 분류해 구성하는 것을 말한다.

 

예시로 고양이를 생각해보자.

 

귀엽다

 

터키시 앙고라, 브리티시 숏헤어, 러시안 블루 등등..세상에는 정말 다양한 '종'의 고양이가 있다. 이 때 우리가 흔히 부르는 '종'이라는 것에 대해 잠시 생각해보자. '종'이란 무엇일까? '종'은 결국 고양이라는 공통적인 특징을 갖고 있지만 세부적으로는 다른 특성과 능력(어찌 보면 기능)을 가지고 있는 고양이들을 인간이 '분류'하기 편하게 설정해 놓은 표준이다.

 

위 논리를 적용했을 때, 개발자의 관점에서 봤을 때 '종'에 따라 분류된 고양이들은 각각의 '객체'로 볼 수 있다.

 

자바스크립트에서 '객체'는 "데이터와 기능이 함께 있다"라는 원칙에 따라 메서드(기능)속성(특징)이 존재한다.

 

그렇다면 고양이들의 메서드와 속성은 무엇일까?

 

먼저 고양이를 개발자의 시선에서 간략하게 '객체'화 시켜보았다.

 

고양이들의 속성

위 코드에서 고양이들은 품종명, 털길이, 특징에 따라 나뉘어져 있고 각 '종'에 따른 고양이들은 모두 다른 특징(속성)을 데이터로 가지고 있다. 만약 우리가 고양이 분양을 위한 웹사이트를 만든다고 했을 때, 위와 같은 식으로 고양이들을 분류해 놓는다면 웹사이트의 관리가 더 쉬울 것이고, 유저들도 찾고자 하는 고양이를 더 빠르게 찾을 수 있어 편의성이 증가할 것이다.

 

고양이들의 (공통) 기능

 

또한 위와 같이 고양이들을 각각의 객체로써 분류했을 때, 모든 고양이는 공통적인 기능(메서드)을 가지고 있다. 야옹 소리 내며 울기, 사뿐사뿐 걷기, 캬악! 하고 성질부리기 등의 기능이 존재하며, 속성으로 품종, 털길이, 대표적인 특징 등과 같은 고유한 데이터 또한 가질 수 있다. 따라서 우리는 '고양이'라는 기본 틀을 가지고 있을 때 원하는 특징을 가진 '종'의 고양이를 객체로써 생성할 수 있다.

 

그렇다면 자바스크립트에서 '객체'를 생성하기 위해서는 어떻게 해야 할까? 앞서 말한 것 처럼 클래스라는 '틀'을 바탕으로 한 고양이라는 (인스턴스) '객체'를 생성하면 된다.


 

클래스(class)와 인스턴스(instance)

 

개발자가 보는 세상

앞의 예시에서, 고양이라는 공통적인 '틀'을 이용하고 각 고양이들을 특성과 기능에 맞게 '객체'로써 생성시켰다. 자바스크립트에서 이 틀(또는 청사진blueprint)을 클래스Class라고 하며 클래스를 통해 생성된 객체를 인스턴스 객체Instance object라고 부른다.

 

 

클래스를 생성할 때는 두 가지 방법을 통해 생성할 수 있는데, 함수로 정의하는 방법과 class 키워드를 통해 만드는 방법이 있다. 함수로 클래스를 정의하는 방법은 자바스크립트에 ES6 업데이트가 도입되기 전까지 써 왔던 방법이다. 최근에는 ES6 방법을 주로 사용하지만, 함수로 클래스를 정의하는 방법이 있음을 알고 있도록 하자. 

 

클래스를 생성하고 그에 걸맞게 인스턴스 객체를 생성할 수 있다.

 

class 키워드를 사용할 때는 안에 제공되는 생성자constructor 함수를 통해 저장하고자 하는 데이터값(속성)을 설정할 수 있다. 생성자 함수에 설정되는 매개변수는 개발에 필요로 하는 데이터값을 받기 때문에 저장하고자 하는 데이터값이 무엇인지 알 수 있는 키워드를 사용하는 것이 좋다.

 

생성자 함수 안에 사용된 this 키워드는 함수가 실행될 때, 해당 스코프마다 생성되는 고유한 실행 컨텍스트context를 가리킨다.

 

예시의 하단처럼 클래스를 통해 인스턴스 객체를 생성할 경우 new 키워드를 사용하는데, 해당 인스턴스가 바로 this의 값이 된다. 즉, 예시에서의 "this.품종명"은 인스턴스 객체의 키key '품종명(cat1의 경우 '브리티시 숏헤어')' 속성property에 해당하는 '값value'이 된다.

 


객체 지향 프로그래밍(OOP)을 왜 쓰는걸까?

객체 지향 프로그래밍을 활용하는 주된 이유는 코드를 단순화하고 재사용성을 높이기 위해서 사용한다. 즉, 썼던 코드를 적절히 활용해서 시간 낭비를 줄일 수 있다.

 

이에 따라 객체 지향 프로그래밍은 네 가지 개념을 가지고 있다.

 

캡슐화 (Encapsulation) 

캡슐화란 데이터(속성)와 기능(메서드)을 하나의 객체 안에 묶어 놓는 것을 말한다. 이를 느슨한 결합 (Loose Coupling)이라고 하는데, 느슨한 결합은 코드 실행 순서에 따라 절차적으로 코드를 작성하는 것이 아닌 코드가 상징하는 실제 모습과 닮게 코드를 모아 결합하는 것을 의미한다.

 

위의 구조에 따라 캡슐화는 내부 데이터나 내부 구현이 외부로 노출되지 않고 객체 외부에서 필요한 메서드만 노출시킬 수 있다. 이러한 특성을 "은닉화"라고 한다. 은닉화의 특징을 활용해 코드를 작성할 경우 객체 내 메서드의 구현만 수정하고 외부에 노출된 메서드를 사용하는 코드 흐름을 방해하지 않을 수 있다. 

 

단, 자바스크립트에서 은닉화는 자바나 타입스크립트와 다르게 private 키워드를 사용하지 못하기 때문에 클래스 내부에서만 속성 및 메서드를 구분시킬 수 없다는 한계가 있다. 이를 보완하기 위해서는 클로저 모듈 패턴을 사용해야 한다.

 

추상화 (Abstraction)

추상화란 복잡한 내부 구현에 비해 노출되는 외부를 단순화하는 개념이다.

 

위의 예시처럼 Human이라는 클래스는 실질적으로 더 복잡한 내부 코드(생성자 함수, 내장 메서드)를 가지고 있지만, 외부에서 Human 클래스를 사용할 때는 이러한 복잡한 내부를 들여보지 않아도 된다. 이는 사용자 인터페이스를 단순화할 수 있는 강점이 된다.

 

사용자 인터페이스가 단순화되면 필요한 기능만 노출할 수 있기 때문에 예기치 못한 사용상의 변화를 방지할 수 있다. 단, 추상화는 캡슐화와 다른 개념이다.

 

캡슐화는 코드나 데이터의 은닉이 주 목적이고, 추상화는 클래스를 사용하는 사람(유저)이 필요로하지 않는 메서드 등을 노출시키지 않는 단순한 인터페이스를 형성하는 것이 주 목적이다.

 

단, 자바스크립트는 은닉화 때와 같이 interface 키워드를 사용할 수 없다는 한계점이 있다. interface 키워드를 사용하면 인터페이슬 통해 메서드 이름이 의도한 바대로 작동할 것이라는 가이드를 제시할 수 있는데, 특정 클래스가 외부 공개용으로 모듈처럼 작동할 때 매우 유용하다.

 

상속 (Inheritance)

상속은 부모 클래스의 특징을 자식 클래스가 물려받는 것을 말한다.

 

부모 클래스를 물려받기 위해서는 extends 키워드 super 키워드를 사용한다.

 

extends를 통해 기존 클래스에서 부모 클래스의 요소를 가져오고, 부모 클래스의 데이터를 생성자 함수 안에 super 키워드를 통해 상속한다. 또한 부모 클래스의 함수를 그대로 활용하면서 부모 클래스가 가지고 있던 함수에 덧붙여 새로운 함수를 사용할 수 있다.

 

다형성 (Polymorphism)

다형성이란 객체에 따라 같은 메서드라도 다른 방식으로 구현할 수 있음을 말한다.

 

위의 예시처럼 세 개의 클래스는 모두 Human이란 부모 클래스를 가지고 있지만 .interview() 메서드에서 출력값이 각각 다르게 나온다. 이는 부모 요소로부터 메서드를 그대로 사용하되, 자식 클래스는 해당 객체의 성격에 맞게 메서드를 개량했다는 뜻이다. 하지만 모두 '자신을 소개한다.'는 특성을 가지고 있기 때문에 .introduce()라는 메서드를 부모 클래스가 갖고 있는 것이 합리적이다.

 

다형성은 이를 통해 if / else 조건문 등을 사용하지 않고도 객체의 특성에 맞게 다양한 객체를 부모 클래스를 통해서 생성할 수 있다는 강점을 가지고 있다.

 


참조

 

댓글