You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
먼저 객체지향 프로그래밍에 대해 알아볼 필요가 있다고 생각했습니다.
객체지향 프로그래밍은 class를 기반으로 한 객체단위로 코드를 나누고 상호작용 하도록 개발하는 프로그래밍 기법입니다.
비교해볼만한 개념으로는 절차지향 프로그래밍이있다.
프로시저(procedure)를 이용하는데, 대학생 때 자바를 처음 배우며 이클립스에디터로 세가지로 나눠서 개발을 해본적이 있다.
- main 문(루틴)
- main문 밖의 내용 중 리턴값 없음(서브루틴)
- main문 밖의 내용 중 리턴 값 있음(함수)
-> main문만 실행시킴
장점도 분명 존재한다. 구조적인 프로그래밍이 가능하고 컴퓨터 처리구조와 유사하게 구현가능
단점은 유지보수가 어렵고 가독성이 안좋다.
그래서 유지보수하기 좋고 가독성 좋은 (재사용성도 높은) 객체지향을 선호하게 되었다.
자바스크립트는 분명 프로토타입을 기반으로한 객체지향 언어임에도 class의 개념은 ES6부터 지원한다.
(그전에는 프로토타입을 활용해서 상속읙 개념을 구현했다는 뜻이기도하다.......)
아무튼 객체지향 프로그래밍의 특징은
1. 캡슐화 - 비슷한 역할을 하는 속성(변수) 행위(함수)를 묶어 접근지정자를 통해 제어
2. 추상화 - 슈퍼클래스(이건 꼭 포함해서 가지고가세요or이건 꼭 구현하세요)를 선정하는 개념이다.
3. 상속 - 새거 만들 때 이미 있는 기능은 가져다 덧붙여서 만드세요
4. 다형성 - 이미 있는거 좀 바꿔서 쓸 수도 있어요(오버라이드(override))
접근제어자는 아래 세가지가 있고 가독성과 유지보수를 위해 표기를 잘 해주는게 좋다 (잊어버릴때가 되서 다시 적는다..)
public: 어디서나 접근가능~ (타입스크립트에선 표기안해줄경우 default가 퍼블릭이다)
protected: 자식까지만 접근가능
priavate: 클래스 내에서만 접근 가능
1. 클래스/ 인터페이스
// class는 js와 크게 다를게 없음classPerson{constructor(name){// js에서는 인스턴스 변수를 선언하지 않아도 this키워드로 자동생성this.name=name;}}// ts에서는 name 변수 선언이 필요함classPerson{name: string;// 이름(인스턴스변수)constructor(name: string){// js에서는 인스턴스 변수를 선언하지 않아도 this키워드로 자동생성this.name=name;}}constperson1: Person=newPerson('gayoung');console.log(person1);// 상속 (extends로 상속함)// – 1부모 다자식 가능, 자식은 부모꺼, 조상님꺼 다 쓸수있지만(override해서 수정해서도 사용가능) 부모는 자식꺼 못씀// Person은 수퍼클래스 Asian은 서브클래스가됨classAsianextendsPerson{nation: string;// 국가constructor(name: string,nation: string){super(name);// 상위 클래스 생성자 호출this.nation=nation;}getName(): string{returnthis.name;}getNation(): string{returnthis.name;}}constkoreanPerson1: Asian=newAsian('gayoung','korea');console.log(koreanPerson1.getName(),koreanPerson1.getNation());
// 클래스는 상태(데이터)와 행동(메소드)을 모두 포함// 인터페이스는 행동만을 정의하고, 인스턴스화될 수 없음interfacePerson{name: string;// 이름setName: (name: string)=>void;getName: ()=>string;}// Asian은 name과 nation 두가지 타입을 가진다.interfaceAsianextendsPerson{// 인터페이스 확장nation: string;// 국가setNation: (nation: string)=>void;// nation 설정 메소드getNation: ()=>string;// nation 반환 메소드}letasianPerson: Asian={name: '기본 이름',nation: '가영',setName(newName: string){this.name=newName;},getName(){returnthis.name;},setNation(newNation: string){this.nation=newNation;},getNation(){returnthis.nation;}};
자주사용하는 키워드 (상속)
extends: 클래스 상속, 인터페이스 확장
implements: 클래스가 인터페이스 내용 구현하도록 강제
// 자바스크립트에는 실제로 extends만 존재하고 interface나 implemnets개념은 없음.
// 하지만 컴파일 단계(개발환경)까지는 동작하며 규칙을 벗어나는지 검사해주기때문에 용도에 맞게 사용합시다.
interface A {}
interface B extends A { }
class A { }
class B extends A { }
interface A { }
class B implements A { }
2. 캡슐화
// 접근제어자를 통해 class를 캡슐화하고 데이터의 무결성을 보장해봅시다.// protected 접근제어자는 타입스크립트 컴파일될때까진 유효 자바스크립트에서는 지원안함classPerson{name: string;// 이름 (은 개명신청이 가능해요, 디폴트 퍼블릭)privatenation: string;// 국가 (태어난 곳은 못바꿔용)constructor(name: string,nation: string){this.name=name;this.nation=nation;}publicgetName(){returnthis.name;}publicgetNation(){returnthis.nation;}// 개명 신청해요~privatesetName(newName: string){returnthis.name=newName;}}
3. 다형성
// 행동만 정의하고 오버라이드해서 사용하돌록 할꺼라 interface 사용interfaceAnimal{makeSomeNoise: ()=>void;}// 인터페이스를 상속받을 때는 "implememnts" 키워드를 쓴다 ( 클래스는 extends )// implements는 클래스가 특정 인터페이스의 계약을 준수하도록 강제 => makeSomeNoise 필수구현classCatimplementsAnimal{makeSomeNoise(): void{console.log('냐용');}}classDogimplementsAnimal{makeSomeNoise(): void{console.log('�멍멍');}}
4. 추상화
// 추상클래스 Animal 선언abstractclassAnimal{// 모든 동물은 인스턴스생성시 이름을 지정해주세요constructor(publicname: string){}// 추상메소드 makeSomeNoise, 구체적인 구현은 하위클래스에서 반드시 해야함abstractmakeSomeNoise(): void;// 모든 동물은 음식을 먹고 대사를해요eat(): void{console.log(`${name} is eat`);}}classCatextendsAnimal{// 추상클래스를 상속받았으면 추상클래스를 구현해요makeSomeNoise():void{console.log('냐옹');}}classDogextendsAnimal{makeSomeNoise(): void{console.log('멍멍');}// dog만의 클래스 확장 가능sleep():void{console.log('dog is sleep');}}constcat1=newCat('kong');cat1.makeSomeNoise();cat1.eat();constdog1=newDog('puppy');dog1.makeSomeNoise();dog1.eat();dog1.sleep();
5. 제어의 역전 (Inversion of Control, IoC) + 의존성 주입
흐름을 개발자가아닌 라이브러리/프레임워크가 관리하는 개념
장점: 개발자는 비즈니스로직에만 집중함, 재사용성 유지보수성 올라감
전통(옛날)방식: 흐름도 개발자가 직접 개발함, 객체 생성 의존성 관리, 어플리케이션 생명주기도 직접 제어
제어의 역전 방식: 대부분 라이브러리/프레임워크가 처리해줌 개발자는 요청만함
ex. 리액트 컴포넌트 생명주기 componentDidMount, ComponentDidUpdate, UseEffect등 제공함. 개발자는 가져다 사용만 함
mobx와 같은 전연 상태를 관리할 때 프레임워크에서는 createContext를 만들고 Provider를 제공하면
개발자는 <createContext.Provider value={전역상태}>{children}<createContext.Provider> 요청만함
의존성주입(Dependency Injection, DI) 는 제어의 역전 원칙을 구현하는 방법
간단한 의존성 주입(DI) 예제
// 의존성 Logger 서비스classLogger{log(message: string){console.log(message);}}// 사용자 클래스classApplication{privatelogger : Logger;constructor(logger: Logger){// 로거 의존성 주입!this.logger=logger;}run(){this.logger.log('로그를찍어용');}}// 메인함수에서 의존성 주입constlogger=newLogger();constapp=newApplication(logger);app.run()// 이렇게 구현하면 Logger와 application을 분리해서 개발할 수 있다. (유연함 업 확장성 업) 테스트도 용이함// 어플리케이션은 로거에 의존한다고 볼 수 있다.// 훅스로 기능을 공통화시킬 때이렇게 많이 썻다
내가 자주 사용하는 mobx에서의 DI예제
importReact,{createContext,useContext}from'react';importhttpSerivcefrom'./httpService';// 서비스 인터페이스// 의존성 : 의존성을 정의하는 인터페이스interfaceglobalService{httpService: (): void;}// 컨텍스트 생성 (컨텍스틀 만들어놓고 다른 컴포넌트에서 사용할때도 컨텍스트를 사용할꺼에요)// globalService를 사용하여 의존성을 주입하기 위한 컨텍스트를 생성합니다.constServiceContext=createContext<globalService|null>(null);// 프로바이더 컴포넌트// 전역 상태를 관리하고싶은 곳에서 호출합니다// 의존성 주입: 이 컴포넌트는 globalService를 리액트 컴포넌트 트리에 주입하는 역할을 합니다.exportconstServiceProvider: React.FC=({children})=>{// 서비스 객체 생성constservice: globalService={httpService: newhttpService();}// 프로바이더로 하위컴포넌트에도 제공return(<ServiceContext.Providervalue={service}>{children}</ServiceContext.Provider>)}// 컨텍스트 사용을 위한 훅exportconstu=seService=(): globalService=>{// useContext를 사용하여 'ServiceContext'로부터 서비스 객체를 받아옵니다constcontext=useContext(ServiceContext);// null 처리if(!context){thrownewError('useService must be used within a ServiceProvider');}returncontext;}