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

sooyoung choi·2023년 12월 1일
0

Javascript, Node.js

목록 보기
29/37
post-thumbnail

📦 객체지향?

  • 소프트웨어 개발에서 주요 구성요소를 기능이 아닌 객체(여러 속성 + method(행동))로 삼으며 어떤 객체가 어떤 일을 할 것인가에 초점을 맞춘다.
    객체를 도출하고 각각의 역할을 명확하게 정의하는 것에 초점을 맞춘 방법론
  • 캡슐화, 다형성, 상속을 지원하고, 데이터 접근 제한 가능하다.


💻 객체 지향 프로그래밍, OOP

  • Object-Oriented Programming, OOP

  • 상태와 데이터를 조작하는 프로세스(method)가 같은 모듈 내부에 배치되는 프로그래밍 패러다임

    프로그래밍 패러다임?

    • 프로그래밍의 방식이나 관점을 바탕으로 효율적이고 명확한 코드를 작성하는 방법
    • 구조적 프로그래밍(기능 중심적), 객체 지향 프로그래밍(프로그램의 처리단위가 객체), 함수형 프로그래밍(함수 중심적)
  • 코드를 추상화 하여 개발자가 더욱 직관적으로 사고할 수 있게 한다.

  • 현실 세계의 객체(사람, 동물, 물건 등)를 유연하게 표현 가능하다.

  • 객체는 고유한 특성을 가지며, 특정 기능을 수행 가능하다.

  • ex) 자동차 -> 문제발생 -> 고장난 부분의 객체 내부만 살펴보면 된다.

    코드는 가독성이 좋아야 하고, 재사용성이 높아야 하고, 유지보수가 쉬워야 한다.


✨ OOP 핵심 원칙

1. 💊 캡슐화

  • 집 안을 외부에 노출시키지 않기 위해 현관문을 잠근다.
  • 현관문 -> 데이터 접근 제한 메서드

1) private

  • TypeScript에서 지원한다.
  • 인스턴스 내부에서만 해당 변수에 접근 가능하도록 제한하는 문법이다.

2) getter / setter

  • getter: 변수 값을 가져온다.
  • setter: 변수 값을 설정한다.
/** Encapsulation **/
class User {
  private name: string; // name 변수를 외부에서 접근을 할 수 없게 만듭니다.
  private age: number; // age 변수를 외부에서 접근을 할 수 없게 만듭니다.

  setName(name: string) { // Private 속성을 가진 name 변수의 값을 변경합니다.
    this.name = name;
  }
  getName() { // Private 속성을 가진 name 변수의 값을 조회합니다.
    return this.name;
  }
  setAge(age: number) { // Private 속성을 가진 age 변수의 값을 변경합니다.
    this.age = age;
  }
  getAge() { // Private 속성을 가진 age 변수의 값을 조회합니다.
    return this.age;
  }
}

const user = new User(); // user 인스턴스 생성
user.setName('최수영');
user.setAge(27);
console.log(user.getName()); // 최수영
console.log(user.getAge()); // 27
console.log(user.name); // Error: User 클래스의 name 변수는 private로 설정되어 있어 바로 접근할 수 없습니다.

2. 🧬 상속

  • 하나의 클래스가 가진 특징(함수, 변수 및 데이터 등)을 다른 클래스가 그대로 물려 받는 것
  • 이미 정의된 상위 클래스의 특징을 하위 클래스에서 물려 받아 코드의 중복을 제거하며, 코드의 재사용성을 증대시킨다.
  • 클래스 간 체계적 구조를 쉽게 파악 가능하며, 전체 코드에 대한 일관성 유지가 가능하다.
/** Inheritance **/
class Mother { // Mother 부모 클래스
  constructor(name, age, tech) { // 부모 클래스 생성자
    this.name = name;
    this.age = age;
    this.tech = tech;
  }
  getTech(){ return this.tech; } // 부모 클래스 getTech 메서드
}

class Child extends Mother{ // Mother 클래스를 상속받은 Child 자식 클래스
  constructor(name, age, tech) { // 자식 클래스 생성자
    super(name, age, tech); // 부모 클래스의 생성자를 호출
  }
}

const child = new Child("최수영", "27", "Node.js");
console.log(child.name); // 최수영
console.log(child.age); // 27
console.log(child.getTech()); // 부모 클래스의 getTech 메서드 호출: Node.js

3. 🔮 추상화

  • 객체에서 공통된 부분만을 모아 상위 개념으로 새롭게 정의 하는 것
  • 불필요한 세부 사항을 생략하고 중요한 특징만을 강조한다.
  • 공통적 특성을 더욱 명확하게 파악할 수 있다.
  • 전체 시스템 구조를 명확하게 이해하게 되고, 테스트를 더욱 쉽게 작성할 수 있게 된다.
/** Abstraction **/
interface Human {
  name: string;
  setName(name);
  getName();
}

// 인터페이스에서 상속받은 프로퍼티와 메소드는 구현하지 않을 경우 에러가 발생합니다.
class Employee implements Human {
  constructor(public name: string) {  }
  
  // Human 인터페이스에서 상속받은 메소드
  setName(name) { this.name = name; }
  
  // Human 인터페이스에서 상속받은 메소드
  getName() { return this.name; }
}

const employee = new Employee("");
employee.setName("최수영"); // Employee 클래스의 name을 변경하는 setter
console.log(employee.getName()); // 최수영 Employee 클래스의 name을 조회하는 getter

클래스 설계 시 공통적으로 묶일 수 있는 기능을 [ 추상화 -> 추상 클래스 -> 인터페이스 ] 순으로 정리한다면?

  • 여러 클래스 간의 일관성을 유지하면서, 다양한 형태로 확장될 수 있는 코드 및 다형성을 구현해낼 수 있다.

4. 🎭 다형성

  • 하나의 객체(클래스)가 다양한 형태로 동작하는 것을 의미한다.
  • 객체가 가진 특성 따라 같은 기능이 다르게 재구성되는 것을 의미한다.
  • 동일한 메서드나 함수명 사용해도 클래스마다 다 다르게 동작하는 것이 다형성의 핵심이다.

1) Overloading

  • 같은 이름의 메서드를 지원하지만, 매개 변수의 유형과 개수를 다르게 해야 쓸 수 있는 것

2) Overriding

  • 상위(부모) 클래스가 갖고 있던 메서드를 하위(자식) 클래스에서 재정의하여 사용하는 것
/** Polymorphism **/
class Person {
  constructor(name) { this.name = name; }

  buy() {}
}

class Employee extends Person {
  buy() { console.log(`${this.constructor.name} 클래스의 ${this.name}님이 물건을 구매하였습니다.`); }
}

class User extends Person {
  buy() { console.log(`${this.constructor.name} 클래스의 ${this.name}님이 물건을 구매하였습니다.`); }
}

const employee1 = new Employee("최수영");
const employee2 = new Employee("베베");
const user1 = new User("김진숙");
const user2 = new User("최관선");

const personsArray = [employee1, employee2, user1, user2];
// personsArray에 저장되어 있는 Employee, User 인스턴스들의 buy 메소드를 호출합니다.
personsArray.forEach((person) => person.buy());

// Employee 클래스의 최수영님이 물건을 구매하였습니다.
// Employee 클래스의 베베님이 물건을 구매하였습니다.
// User 클래스의 김진숙님이 물건을 구매하였습니다.
// User 클래스의 최관선님이 물건을 구매하였습니다.


0개의 댓글