객체 지향 프로그래밍

kirin.log·2021년 8월 14일
0

🍺 객체 지향 프로그래밍

  • 프로그램을 객체(object)의 집합으로 보는 패러다임을 뜻함
    ( <-> 명령형 프로그래밍, 절차형 프로그래밍)

  • 객체 지향 프로그래밍 패러다임을 따른다는 것은, 하나의 모델(Class)을 만들고 이 모델을 바탕으로 한 객체(object)를 만든다는 것을 의미한다.

    객체(object)란 상태 데이터(=속성, attributes, properties)와 동작(=메소드, method)을 하나의 논리적 단위로 묶은 복합적인 자료구조

  • 모델(Class)을 따라 만들어진 것이 객체(object)이면서 그 클래스의 인스턴스(instance)가 된다.

🍺 객체 지향 프로그래밍의 4가지 핵심 개념

1) 캡슐화(encapsulation)
2) 추상화(abstraction)
3) 상속(inheritance)
4) 다형성(polymorphism)

캡슐화(encapsulation)

객체의 상태(state)를 나타내는 속성과 그 속성들을 참조하고 조작할 수 있는 동작인 메소드를 하나로 묶는 것을 뜻한다. 바로 객체 지향 프로그래밍의 기본적인 객체 구성 형태를 묘사하는 단어인 것이다.

속성과 메소드를 한 곳에 캡슐처럼 묶기 때문에 이 개념에는 은닉(hiding)의 개념까지 포함되어 있다. 객체의 특정 속성이나 메소드를 감출 목적으로 캡슐화를 사용할 수도 있기 때문이다. (예: 클로저)
이를 통해 디테일한 구현은 숨기지만, 동시에 동작은 노출시키는 것이 가능해진다.

추상화(abstraction)

객체가 가진 여러 속성들 중에서 사용자가 필요한 속성만 간추려내어 표현하는 것을 뜻한다.

  • 그림 왼편에 있는 아이콘(사람, 가방)은 현실세계의 물체를 뜻한다.
  • 가운데 박스(Person, Job)는 현실세계의 물체 속성들 중에서 객체로 만들려는 프로그램에 필요한 속성들만 골라놓은 작업을 진행한 결과인 클래스(Class)이다.
    (=추상화가 진행된 결과)
  • 오른편의 동그라미가 나타내는 것은 추상화 작업이 끝난 클래스를 기반으로 생성한 인스턴스들이다.

캡슐화가 데이터의 은닉에 포커스가 맞추어져 있다면, 추상화 같은 경우 클래스를 사용할 때 필요하지 않은 부분은 굳이 노출시키지 않는 것에 초점이 맞추어져 있는 것이다.
즉, 인터페이스의 단순화 를 추구한다고도 표현할 수 있다.

상속(inheritance)

객체의 프로퍼티 또는 메소드를 다른 객체가 상속받아 그대로 사용할 수 있는 것을 말한다. 즉, 부모 클래스(base class)의 특징을 자식 클래스(derived class)가 물려받는 특성을 뜻한다.

객체 지향 프로그래밍에서는 상속의 특성이 있기 때문에 코드의 재사용성을 높일 수 있다.

다형성(polymorphism)

객체의 프로퍼티 또는 메소드를 다양한(poly) 형태(morph)로 변형시켜 사용할 수 있는 것을 말한다. 즉, 다형성은 동일한 인터페이스 상에서 다른 종류의 다양한 객체들을 사용할 수 있도록 해준다


위 그림과 같이 모든 동물들은 다른 소리를 낸다. 이렇듯 다른 소리를 내는 동물들을 동물이라는 동일한 클래스를 만들어진 인스턴스라고 생각해보자.
그렇다면 말하는 행위(speak())라는 하나의 메소드로 표현할 수 있다.
이 동물 인스턴스들은 모두 동일한 speak()라는 메소드 인터페이스 상에서 작동하지만, 나오는 결과물인 소리는 모두가 다를것이다.
(만약 다형성이 존재하지 않는다면 반복적으로 speak() 기능을 각각의 동물들에게 넣어주는 반복적인 행위를 지속해야 할것이다)

❗ 현실세계에서의 객체지향적 프로그래밍 예시
<토끼>

  • properties
    • 귀: 길다
    • 외모: 동글동글하다
    • 털: 복슬복슬하다
    • 색: 흰색
  • methods
    • 당근을 먹는다
    • 뛴다
const rabbit = {
  // property
  ear: 'long',
  appearance: 'rounded',
  hair: 'fluffy',
  color: 'white',
 
  // method
  eatCarrots: function(numOfCarrots) {
    let eat = 1;
    eat = eat : numOfCarrots;
    return eat;
  },
  run: function(fondness) {
    let distance = 1;
    distance = -(distance + fondness)
    return distance;
  }
}

🍺 클래스를 만드는 두 가지 방법(javascript)

1) ES6 도입 전 : 함수를 사용하는 방식
2) ES6 도입 후 : 클래스 성성자를 이용하는 방식
❗ 클래스를 만들 땐 통상적으로 맨 앞글자를 대문자로 만든다

// 방법1) 함수를 사용한 방식
function Sword(name, color, damage) {
    this.name = name;
    this.color = color;
    this.damage = damage;
}
// 방법1) 메소드
function.prototype.attack = function() {
  // (공격)
}
function.prototype.defend = function() {
  // (방어)
}


// 방법2) 클래스 생성자를 사용한 방식
class Sword {
  constructor(name, color, damage) {
    this.name = name;
    this.color = color;
    this.damage = damage;
  }
  // 방법2) 인스턴스 메소드
  attack() {
    // (공격)
  }
  defend() {
    // (방어)
  }
}

❗ 인스턴스 메소드( = attack(), defend())를 만들면 클래스로부터 새로이 만들어진 인스턴스가 
자유롭게 사용할 수 있는 그 클래스의 메소드로 사용된다 

🍺 인스턴스(instance) 만들기

// Sword 클래스의 "인스턴스"
let myKnife = new Sword('big knife', 'red', '999999')new 키워드를 사용해서 만든 모든 인스턴스들은 자신을 만드는데 모티브가 되어 준 클래스의 
인스턴스 메소드(attack(), defend())를 사용할 수 있다.

// Sword 클래스의 "메소드"를 아래와 같이 사용할 수 있다
myKnife.attack()
myKnife.defend()

위 예시처럼 Class내 메소드(attack(), defend())는 프로토타입 메소드 라고도 불린다.
이는 Class를 통해 만들어진 인스턴스에서 아무런 제약 없이 사용할 수 있다.

💡 반면에, 정적 메소드(static method)라 불리는 것들은 인스턴스가 사용할 수 없는 메소드들을 뜻한다.
정적 메소드는 일반 메소드들과는 다르게 앞에 static이라는 키워드가 붙은 변수 또는 함수들을 뜻한다.

따라서 정적 메소드는 클래스(Class) 본체만 호출할 수 있다. 인스턴스에서는 호출할 수 없다.

🍏 static - 정적 메소드

class Sword {
  constructor(name, color, damage) {
    this.name = name;
    this.color = color;
    this.damage = damage;
  }

  static attack() {       // static이 붙은 정적 메소드 (Class에서만 호출 가능)
    // (공격)
  }
  defend() {     // 일반 메소드 (인스턴스에서 호출 가능)
    // (방어)
  }
}

위 Class 내 2개의 메소드(attack(), defend()) 중에서 static이 붙은 메소드는 클래스 단위에서만 호출할 수 있다(인스턴스는 호출 불가능)

따라서 아래와 같이 호출할 수 있다

// Sword 클래스의 "인스턴스"
let myKnife = new Sword('big knife', 'red', '999999')

Sword.attack()    // static이 붙었기 때문에 Class로부터 호출할 수 있는 메소드
myKnife.defend()  // 인스턴스(myKnife)에서 호출할 수 있는 메소드

즉, static 키워드는 클래스의 정적인 메소드 또는 프로퍼티를 정의한다. 정적 메소드와 정적 프로퍼티는 클래스의 인스턴스로부터 호출될 수 없다. 대신 클래스 그 자체로 호출을 해야한다.

정적 메소드(staitc 키워드가 붙은 변수 또는 함수)는 객체를 생성하거나 복제하는 기능과 같은 유틸리티 기능에 사용된다.
정적 프로퍼티는 캐시, 고정된 설정, 또는 각 인스턴스마다 복제할 필요가 없는 데이터 등을 만들 때 유용한다.

🍏 constructor - 생성자

생성자(constructor)는 new연산자와 같이 사용되어, 클래스로부터 객체를 생성할 때 호출되어 객체의 초기화를 담당한다.

  • 인스턴스 변수의 초기화 작업에 주로 사용되며, 인스턴스 생성 시에 실행되어야 할 작업을 위해서도 사용된다.
  • new연산자에 의해 생성자가 성공적으로 실행되면, 메모리 힙(Heap) 영역에 객체가 생성되고 객체의 주소가 return된다. return된 객체의 주소는 클래스 타입 변수에 저장되어 객체에 접근할 때 이용된다.
  • 모든 클래스는 생성자가 반드시 존재하며, 하나 이상을 가질 수 있다.
    (하나의 클래스에 여러 개의 생성자가 있을 수 있다)
  • 생성자의 이름은 클래스의 이름과 같아야 한다
  • 생성자는 return값이 없다.
  • 생성자도 메서드이기 때문에 리턴값이 없다는 의미의 void를 적어야 하지만, 모든 생성자가 return값이 없으므로 void를 생략한다.
class User {

  constructor(name) {
    this.name = name;
  }

  sayHi() {
    alert(this.name);
  }

}

// 인스턴스 만들기
let user = new User("John");
user.sayHi();

new User("John")를 호출하면
1) 새로운 객체가 생성.
2) 넘겨받은 인수와 함께 constructor가 자동으로 실행. 이때 인수 "John"이 this.name에 할당됨.

이런 과정을 거친 후에 user.sayHi() 같은 객체 메서드를 호출할 수 있다.

profile
boma91@gmail.com

2개의 댓글

comment-user-thumbnail
2021년 8월 18일

정리 쵝오!!!

1개의 답글