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

dr7204·2025년 4월 22일

객체 지향 설계와 프로그래밍

  • 객체들이 모여서 상호 협력하면서 데이터를 처리하는 방식

최신 프론트엔드 트렌드는 함수형 프로그래밍이 강조되고 있지만, 객체지향 프로그래밍도 알아두면 좋을 것 같다.

용어

  • 클래스
    • 객체 지향 프로그래밍을 지원하기 위해 ES6에서 도입된 기능이다.
    • 객체를 생성하는 템플릿, 설계도 역할을 하며, 프로토타입 기반의 객체 지향 패턴을 보다 명확하고 쉽게 사용할 수 있게 해준다.
  • 객체
    • 객체는 원시타입과 달리 다양한 데이터를 담을 수 있는 데이터 타입이다.
      • 원시 데이터 타입, 객체, 함수, 배열, Date, 정규표현식, 심볼 등
    • (key)와 (value)로 구성된 프로퍼티(Property)들의 집합이다.
    • ‘클래스의 인스턴스’라고도 부른다.
  • 인스턴스
    • 설계도를 바탕으로 소프트웨어 세계에 구현된 구체적인 실체이다.
    • 인스턴스는 객체에 포함된다고 볼 수 있다.

프로그래밍 구조

  • 프로퍼티와 메소드
    • 프로퍼티(property)
      • 객체에는 ‘키 : 값’ 쌍으로 구성된 프로퍼티가 들어간다.
      • 프로퍼티 값엔 모든 데이터 타입이 올 수 있다.
      • 하지만 몇몇 데이터 타입은 어떤 경우에 동작하지 않거나 원치 않은 결과를 불러올 수 있다.
        • NaN, Infinity, BigInt, undefined, null
    • 메서드(method)
      • 객체 안에 프로퍼티로 정의된 함수를 메서드라고 한다.

        const obj = {
         f1 : function () {
           console.log("hi!")
         },
         f2(){
           console.log("hi!")   
         }

        기존에는 f1의 형태처럼, 프로퍼티를 정의할 때와 동일하게 선언했었는데,

        ES6에서는 f2와 같이 : 를 생략한 축약 표현을 사용할 수 있다.

        ES6 이후의 코드를 작성할 때는 더 간결한 축약 메서드 구문을 사용하는 것이 일반적이다.

  • 캡슐화
    • 비슷한 관련된 역할을 하는 속성과 메소드들을 하나의 캡슐로 만들어 외부로 부터 보호하는 것을 말한다.
    • 이유
      • 데이터 보호 : 외부로 부터 각 객체에 정의된 속성과 기능을 보호
      • 데이터 은닉 : 내부의 동작을 감추고 필요한 부분만 노출시키기 위함
    • 프라이빗 필드
      • #을 사용하여 클래스 내에서만 접근 가능한 프라이빗 필드를 정의할 수 있다.
      • 이는 클래스 외부에서 필드에 직접 접근 및 수정하지 못하도록 한다.
      • 단점은 클래스의 상속 구조에서 자식 클래스가 부모 클래스의 프라이빗 필드에 접근할 수 없다는 점을 고려해야 한다는 것이다.
    • getter/setter
      • 예시
        class Person {
          #name; 
          #age;   
          
          constructor(name, age) {
            this.#name = name;
            this.#age = age;
          }
          
          // Getter
          get name() {
            return this.#name;
          }
          
          get age() {
            return this.#age;
          }
          
          // Setter
          set name(newName) {
            this.#name = newName;
          }
          
          set age(newAge) {
            if (newAge > 0) {
              this.#age = newAge;
            }
          }
        }
        
        const person = new Person('John', 30);
        
        console.log(person.name);  // "John"
        console.log(person.age);   // 30
        
        person.name = 'Jane';  // setter 호출
        person.age = 35;       // setter 호출
        
        console.log(person.name);  // "Jane"
        console.log(person.age);   // 35
  • 상속

    • 객체가 다른 객체를 상속 받아 해당 객체의 요소를 사용하는 것을 의미한다.
    • 상속 받은 객체는 자식, 상속된 객체는 부모라 칭한다.
    • 상속을 통해 프로젝트의 생산성, 유지보수성, 재사용성을 높일 수 있다.
  • 다형성

    • 동일한 메시지나 인터페이스가 여러 가지 형태로 동작할 수 있는 것을 의미한다.
    • 메서드 오버로딩(Method Overloading)
      • 같은 이름의 메서드를 여러 개 정의하되, 각 메서드는 서로 다른 매개변수 목록을 가진다.
      • 자바스크립트에서는 이를 직접 지원하지 않지만, 매개변수의 개수와 타입을 체크하며 직접 구현할 수 있다.
    • 메서드 오버라이딩(Method Overriding)
      • 상속을 통해 자식 클래스에서 부모 클래스의 메서드를 재정의하여 사용한다.
    • 상속과 마찬가지로 생산성, 유지보수성, 재사용성을 높일 수 있다.

객체 표현 방식

객체표현 - 1. 리터럴 표기법 (Literal Notation)

  • 중괄호를 사용하여 객체를 정의하며, 속성과 값음 key : value 형식으로 나열한다.
const healthObj = {
  name : "달리기",
  lastTime : "PM10:12",
  showHealth() {
    console.log(this.name + "님, 오늘은 " + this.lastTime + "에 운동을 하셨네요");
  }
}

healthObj.showHealth();

객체표현 - 2. 생성자 함수 (Constructor Function)

  • 객체의 템플릿을 정의하고, new 키워드로 객체를 생성한다. 생성자 함수의 첫 글자는 보통 대문자를 사용하는 것이 관례이다.
const Health = function(name,healthTime) {
  this.name = name;
  this.healthTime = healthTime;
  this.showHealth = function() {
    console.log(this.name + "님, 오늘은 " + this.healthTime + "에 운동을 하셨네요");
  }
}

const ho = new Health("crong", "12:12");
ho.showHealth();

객체표현 - 3. 클래스 문법 (Class Syntax)

  • ES6부터 도입된 문법으로, 생성자 함수보다 직관적이고 상속과 같은 객체 지향적인 개념을 쉽게 사용할 수 있다.
const Health = class {
  constructor(name, healthTime) {
    this.name = name;
    this.healthTime = healthTime;
  }

  showHealth(){
     console.log(this.name + "님, 오늘은 " + this.healthTime + "에 운동을 하셨네요");
  }

}

const ho = new Health("crong", "12:12");
ho.showHealth();

this와 super 키워드 차이점

this

  • 인스턴스 변수와 로컬 변수 구별
    • 인스턴스 변수와 로컬 변수의 이름이 같을 때, this 키워드를 사용하며 인스턴스 변수를 구분할 수 있다.
    • 예시
      class Example {
        constructor(value) {
          this.value = value;  // 인스턴스 변수
        }
        showValue() {
          let value = 10;  // 로컬 변수
          console.log(value); // 출력 : 로컬 변수
          console.log(this.value); // 출력 : 인스턴스 변수
        }
      }
  • 현재 객체 반환
  • 현재 객체의 메서드 호출
    • 같은 클래스 내에서 다른 메서드를 호출

super

  • 부모 클래스의 생성자, 메서드를 호출하거나 인스턴스 변수를 참조할 때 사용된다.

SOLID 원칙

SRP(Single Responsibility Principle) 단일 책임 원칙

  • 한 클래스는 하나의 책임을 가져야 한다는 원칙
  • 클래스가 변경되어야 하는 이유가 단 하나만 있어야 한다는 것이다.
  • 목적 :
    • 유지보수성 향상
    • 변경의 용이성
    • 재사용성 증가
  • 코드 길이가 길어졌다 하더라도, 하나의 클래스를 사용하는 것보다 여러 개의 클래스를 사용하는 것이 더 효율적이다.
  1. 클래스명은 책임의 소재를 알 수 있게 작명
  2. 책임을 분리할 때 항상 결합도, 응집도를 따져가며
    1. 응집도란 한 프로그램 요소가 얼마나 뭉쳐 있는가를 나타내는 척도
    2. 결합도는 프로그램 구성 요소들 사이가 얼마나 의존적 인지를 나타내는 척도

LSP(Liskov- Substitution Principle) 리스코프 교환원칙

  • 프로그램에서 상위 타입의 객체를 하위 타입의 객체로 치환해도 프로그램의 동작이 바뀌지 않아야 한다는 원칙
  • 자식 클래스는 언제나 자신의 부모 클래스를 대체할 수 있어야 한다는 것이다.
  • 사실상 다형성 원리를 얘기하는 것이다.
  • 목적 :
    • 신뢰성 향상
    • 유연성 증가
    • 유지보수성 개선

0개의 댓글