📦 객체지향?
- 소프트웨어 개발에서 주요 구성요소를 기능이 아닌 객체(여러 속성 + method(행동))로 삼으며 어떤 객체가 어떤 일을 할 것인가에 초점을 맞춘다.
객체를 도출하고 각각의 역할을 명확하게 정의하는 것에 초점을 맞춘 방법론
- 캡슐화, 다형성, 상속을 지원하고, 데이터 접근 제한 가능하다.
Object-Oriented Programming, OOP
상태와 데이터를 조작하는 프로세스(method)가 같은 모듈 내부에 배치되는 프로그래밍 패러다임
프로그래밍 패러다임?
- 프로그래밍의 방식이나 관점을 바탕으로 효율적이고 명확한 코드를 작성하는 방법
- 구조적 프로그래밍(기능 중심적), 객체 지향 프로그래밍(프로그램의 처리단위가 객체), 함수형 프로그래밍(함수 중심적)
코드를 추상화 하여 개발자가 더욱 직관적으로 사고할 수 있게 한다.
현실 세계의 객체(사람, 동물, 물건 등)를 유연하게 표현 가능하다.
객체는 고유한 특성을 가지며, 특정 기능을 수행 가능하다.
ex) 자동차 -> 문제발생 -> 고장난 부분의 객체 내부만 살펴보면 된다.
코드는 가독성이 좋아야 하고, 재사용성이 높아야 하고, 유지보수가 쉬워야 한다.
/** 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로 설정되어 있어 바로 접근할 수 없습니다.
/** 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
/** 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
클래스 설계 시 공통적으로 묶일 수 있는 기능을 [ 추상화 -> 추상 클래스 -> 인터페이스 ] 순으로 정리한다면?
- 여러 클래스 간의 일관성을 유지하면서, 다양한 형태로 확장될 수 있는 코드 및 다형성을 구현해낼 수 있다.
/** 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 클래스의 최관선님이 물건을 구매하였습니다.