개발일지
개발일지 42일차
index.ys
2023. 5. 1. 01:46
객체지향 (Object-Oriented)
- S/W의 핵심을 객체로 삼음, 객체를 도출하고 역할을 정의 하는 것 중심
- 모듈 + 모듈 + 모듈 = 객체(class)
- 시스템을 효과적으로 분해하고 구성, 효율적으로 다룰 수 있게하는 프로그래밍 패러다임
객체 지향 구분방법
- 캡슐화, 다형성, 클래스 상속 지원여부
- 데이터 접근 제한 여부
캡슐화 (Encapsulation)
- 객체내부 세부사항을 감춤, 정보은닉 목적
- 정보 노출 방지, 보안성 ↑
- 변경 쉬운 객체, 결합도 ↓
- private: 접근 제어자(인스턴스 내부에서만 해당 변수에 접근 가능하도록 제한)
- 오로지 setter로만 변수 변경, getter로만 변수 조회
캡슐화 예시코드
/** Encapsulation **/
class User {
private name: string;
private age: number;
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(20);
console.log(user.getName()); // 김용식
console.log(user.getAge()); // 20
console.log(user.name); // Error: User클래스의 name 변수는 private로 설정되어 있어 바로 접근할 수 없습니다.
상속 (Inheritance)
- 상위 클래스의 특징( 함수, 변수 데이터 )을 하위클래스에 복사
- 일관성 유지 ,구조 파악
- extends 키워드로 자식 요소에 부모요소를 상속
상속 예시코드
/** 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("마동석", "11", "Node.js");
console.log(child.name); // 마동석
console.log(child.age); // 11
console.log(child.getTech()); // 부모 클래스의 getTech 메서드 호출: Node.js
추상화
- 객체에서 공통된 부분을 모아 상위 개념으로 선언
- 필요없는 특성제거(모델화)
- 구조 및 특성 가시적, 모델을 테스트 하는데 용이함
- Interface키워드를 사용해 메소드와 속성만 정의하여 메소드의 구현강제, 일관성 유지
추상화 예시코드
/** 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)
- 메소드의 이름은 같지만 클래스 별로 메소드의 기능을 다르게 정의
- 오버라이딩을 통해 서비스의 구현기능 변경, 확장 가능
*오버로딩, 오버라이딩*
다형성 예시 코드
- Employee 클래스와 User클래스에서 정의된 buy()메소드는 메소드의 이름은 같지만 클래스가 다르기 때문에 전달 받은 인자에 따라 각각 다른 값을 출력함
/** Polymorphism **/
class Employee {
constructor(name) { this.name = name; }
buy() { console.log(`${this.constructor.name} 클래스의 ${this.name}님이 물건을 구매하였습니다.`); }
}
class User {
constructor(name) { this.name = name; }
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 polymorphismArray = [employee1, employee2, user1, user2];
polymorphismArray에 저장되어 있는 Employee, User 인스턴스들의 buy 메소드를 호출합니다.
polymorphismArray.forEach((polymorphism) => polymorphism.buy());
// Employee 클래스의 마동석님이 물건을 구매하였습니다.
// Employee 클래스의 아이유님이 물건을 구매하였습니다.
// User 클래스의 박서준님이 물건을 구매하였습니다.
// User 클래스의 조진웅님이 물건을 구매하였습니다.
의존성 (Dependency)
- 특정객체가 다른 객체에 의존함, 의존성이 낮아야 변경해야 하는 코드의 양이 달라짐
- 클래스 하나를 변경했을 때, 객체 1 , 2, 3이 상속 받는 속성들이 한꺼번에 변경되므로 의존성을 낮춰야함
결합도 (Coupling)
- 객체 사이의 의존성 ↑ 결합도 ↑
- 의존성 ↓ 결합도↓
- 설계 목표는 객체간 결합도를 낮춰 변경이 용이한 설계
응집도 (Cohesion)
- 요소들이 연관되어 있는 관계정도
- 스스로 자율적인 객체 = 결합도 ↓ 응집도 ↑
- 객체 스스로 자신의 데이터를 책임져야함
객체 지향 프로그래밍 (Object-Oriented Programming, OOP)
구조적 프로그래밍 (Structured Programming)
- 기눙 중심 개발
- 프로그래밍 처음으로 적용된 패러다임
객체 지향 프로그래밍 (Object-Oriented Programming, OOP)
- 처리단위가 객체
- 현실세계를 모델링 하는 대표적 프로그래밍
- ex) 자동차, 동물, 사람, 음식 등을 유연하게 표현
객체 지향 프로그래밍 사용 이유
- 동일한 코드를 한번에 수정 가능
- 오류를 인지하고 시간절약 가능
- 데이터와 프로세스를 하나의 단위로 처리가능
장점
- 의존성을 효율적으로 통제 가능, 요구 사항 변경에 수월한 대응가능
- 데이터중심 프로그래밍 => 일관성
- 에러처리가 용이함
설계
- 이해하기 쉽게설계 => 가독성
- 변경하기 쉽게 설계 => 1변경, 1클래스 수정
- 캡슐화 => 의존성을 관리, 결합도 ↓
함수형 프로그래밍 (Functional Programming)
- 함수를 중심으로 개발
- 처음으로 만들어진 프로그래밍 패러다임, 최근에 도입
객체 지향 설계 5원칙 (SOLID)
- 유지보수와 확장 용이 시스템, 5가지 원칙을 기반으로함
1. 단일 책임의 원칙 (Single Responsibility Principle, SRP)
- 1개의 객체에서는 1개의 책임만 가짐
- 적절한 클래스의 크기를 제시
- 수정시 까지 고려 (멀리보기)
/** SRP Before **/
class UserSettings {
constructor(user) { // UserSettings 클래스 생성자
this.user = user;
}
changeSettings(userSettings) { // 사용자의 설정을 변경하는 메소드
if (this.verifyCredentials()) {
//...
}
}
verifyCredentials() { // 사용자의 인증을 검증하는 메소드
//...
}
}
2. 개방-폐쇄 원칙 (Open-Closed Principle, OCP)
- 엔티티 또는 개체는 확장에는 열려있고, 변경에는 닫혀있음
- 기존 코드에 영향을 주지 않고 새로운 기능이나 구성요소 추가
3. 리스코프 치환 원칙 (Liskov substitution principle, LSP)
- 상위 객체는 하위 타입의 인스턴스로 변경가능
- 부모객체와 자식객체를 서로 바꾸어도 같은 결과 실행해야함
4. 인터페이스 분리 원칙 (Interface segregation principle, ISP)
- 인터페이스를 초대한 작게 유지
- 필요하지 않은 것들에 의존 x, 인터페이스 최소화
- interface 키워드를 사용해 사용할 수 있는 기능을 정의함
5. 의존성 역전 원칙 (Dependency Inversion Principle, DIP)
- 고수준 계층 모듈, 저수준 계층의 모듈 둘다 => 추상화에 의존
- 작은 코드 수정 => 큰 코드 수정을 방지 해야함
아키텍처 패턴(Architecture Pattern)
- 소프트웨어의 구조를 구성하기 위한 토대
- 안정적인 개발 가능
- 코드를 쉽게 변경가능 => 큰 이익
- 저장소 패턴
- 에그리게이트 패턴
- 이익과 비용을 고려
- 장단점 고려
- 앱과 도메인이 복잡할떄 아키텍쳐 패턴을 적용
계층형 아키텍처 패턴(Architecture Pattern)
- 계층을 분리해서관리, 가장많이 사용
- 표준 아키텍처
- 계층을 분리해서 유지, 계층이 자신의 바로 아래 계층에 의존
계층화
- 각 계층 응집도 ↑
- 다른 계층 결합도 ↓
3계층 아키텍처
- 프레젠테이션 계층
- 비즈니스 로직 계층: 비즈니스 로직 처리
- 데이트 액세스 계층: DB와 연결, 데이터 사용
장점
- 계층별 관심사 분리, 코드 내용 인지
- 계층별 유닛 테스트 용이
컨트롤러 (Controller)
- 요청
- 요청에 대한 처리는 서비스에게 전담
- 응답
서비스 (Service)
- 사용자의 요구사항을 처리("비즈니스 로직")
- DB 정보가 필요할 떄는 Repo에 요청
저장소 (Repository)
- DB 관리(연결, 해제, 자원관리)
- DB CRUD 작업 처리
- add(): 추가
- get(): 가져옴
- 가짜 저장소 제공, 테스트 코드 작성 가능
- DB를 간단하게 추상화가능 모델, 데이터 분석
- 단위테스트를 위한 가짜 저장소 가능
- ORM 사용시 DB변경 용이
- ORM이 모델과 저장소의 결합을 완하
할 일: LV5 과제 마무리, 스파르타 코딩클럽, 챌린지 강의 듣고 jest로 테스트 코드 작성하기, node.js 모듈, 라이브러리 간단하게 사용방법 익히기