-
[TIL] 0216 객체 지향 프로그래밍 (OOP), SOLID카테고리 없음 2024. 2. 16. 20:57
객체 (Object)
: 현실 세계의 물체 혹은 개념을 소프트웨어 적으로 옮긴 것으로, 정보 + 행동(method) 으로 구성된다.
객체 지향 (Object-Oriented)
: 객체 도출, 각각의 역할 명확히 정의하는 것에 초점을 맞추는 방법론
: 크고 복잡한 시스템도 효과적으로 분해와 구성이 가능하여, 효율적으로 관리할 수 있다.
객체 지향적 소프트웨어
1) 캡슐화, 다형성, 상속을 지원
2) 데이터 접근 제한 (Access modifier) 가능
<-> 절차 지향 소프트웨어
프로그래밍 패러다임 ( Programming Paradigm )
: 프로그래밍의 방식이나 관점을 바탕으로 효율적이고 명확한 코드를 작성하는 방법
1) 구조적 프로그래밍 : 가장 처음 적용된 패러다임
2) 함수형 프로그래밍 : 함수 중심적으로 개발 진행
3) 객체 지향 프로그래밍
: 데이터와 메서드가 같은 모듈 내부에 배치되는 프로그래밍 방식
: 객체는 고유의 특성 + 특정 기능 을 가진다.
: 데이터와 기능이 밀접하게 연결되어 있어 코드의 구조와 동작을 직관적으로 파악이 가능하다.
객체 지향 프로그래밍 (OOP) 객체 지향 프로그래밍의 원칙
1) 캡슐화 (Encapsulation)
: 객체 내부의 중요한 정보를 외부로 노출되지 않도록 만드는 것
: JS 는 완벽한 캡슐화를 지원하지 않아 개발자들은 변수 앞에 _ 를 붙여 내부 변수를 숨긴 것 처럼 나타낸다.
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;
}
}: 변수의 값을 가져오는 getter (getName, getAge) 만 변수를 조회할 수 있고,
변수의 값을 설정하는 setter (setName, setAge) 만 변수를 변경할 수 있다.
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); // 부모 클래스의 생성자를 호출
}
}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("홍길동");
console.log(employee.getName()); // 홍길동4) 다형성 (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 user1 = new User("이태강");
const user2 = new User("김민수");
const personsArray = [user1, user2];
personsArray.forEach((person) => person.buy());
// User 클래스의 이태강님이 물건을 구매하였습니다.
// User 클래스의 김민수님이 물건을 구매하였습니다.객체 지향 프로그래밍 및 설계의 다섯가지 기본원칙 : SOLID
1) 단일 책임의 원칙 (Single Responsibility Principle, SRP)
: 하나의 객체는 하나의 책임을 가져야 한다는 개념을 가지며, 적절한 클래스의 크기를 제시한다.
2) 개방-폐쇄 원칙 (Open-Closed Principle, OCP)
: 소프트웨어 엔티티 또는 개체(클래스, 모듈, 함수 등) 의 행위는 확장될 수 있어야 하지만, 개체를 변경해서는 안된다.
: 기존 코드에 영향없이 소프트웨어에 새로운 기능이나 구성 요소를 추가할 수 있어야 한다.
OCP 예시 3) 리스코프 치환 원칙 (Liskov substitution principle, LSP)
: 부모 클래스와 자식 클래스를 가지고 있다면, 서로 바꾸더라도 해당 프로그램에서 잘못된 결과를 도출하지 않아야 한다는 원칙
: 원칙에 위배되면, 새로운 부모 클래스를 형성하여 자식 클래스로 넣어 통합시키는 방법 이 있다.
4) 인터페이스 분리 원칙 (Interface segregation principle, ISP)
: 필요없는 것들에 의존하지 않도록 인터페이스는 작고 구체적으로 유지해야 한다는 원칙
: 범용 인터페이스 하나보다 특정 클라이언트를 위한 인터페이스 여러 개가 낫다.
5) 의존성 역전 원칙 (Dependency Inversion Principle, DIP)
: 높은 계층의 모듈(도메인)이 저수준의 모듈(하부구조)에 직접 의존해서는 안된다.
DIP 전 후