OOP

타입
Property
Property 1

polymorphism

const Worker = class { run(){ console.log('working') } print(){ this.run() // 내적 일관성 ( internal identity ) } } const HardWorker = class extends Worker { run() { console.log('hardworking') } } const worker = new HardWorker() console.log(worker instanceof Worker) // 대체 가능성 ( substitution ) worker.print(); // 다형성 = 내적 일관성 + 대채 가능성
JavaScript
복사

Object Essentials

const EssentialObject = class { #name = ''; // hide state -> 필드를 숨김 #screen = null; constructor(name){ this.#name = name; } camouflage(){ this.#screen = (Math.random() * 10).toString(16).replace(".", '') } get name(){ // encapsulation -> 메서드의 기능을 숨김 return this.#screen || this.#name; } } // Encapulation of Functionality // Maintenance of State
JavaScript
복사

Isolation of Change

SOLID

SRP Single Responsibility 단일 책임 (하나의 수정 범위, 하나의 테스트 범위)

산탄총 수술 ( shotgun surgery )

OCP Open Closed 개방폐쇄

LSP Liskov Substitusion 업캐스팅 안전

Polymohpism ( 자식은 부모를 대체 가능하다. )
LSP 위배
LSP에 적합

ISP Interface Segregation 인터페이스 분리

LSP를 해결함
또 다른 예시

DIP Dependency Inversion 다운캐스팅금지

의존성은 부모쪽으로만 흘러야 한다.

Others...

1.
DI Dependency Injection 의존성주입 (IoC Inversion of Control 제어역전)
2.
DRY Don't Repeat Yourself 중복방지
3.
Hollywood Principle 의존성 부패방지
( 물어보지 말고 요청하라 )
번호 좀 줘 → X 번호 필드가 노출됨
연락 해 줄래? → O
4.
Law of demeter 최소 지식 [무시하면 열차전복 (train wreck)이 일어남]
classA.methodA의 최대지식한계
classA의 필드 객체
methodA가 생성한 객체
methodA의 인자로 넘어온 객체

객체 망

1.
메시지 - 의뢰할 내용
2.
오퍼레이션 - 메시지를 수신할 객체가 제공하는 서비스
3.
메소드 - 오퍼레이션이 연결될 실제 처리기
오퍼레이션은 인터페이스에 선언한 기능
메소드는 런타임에서 실제로 실행할 오퍼레이션 ( 동적 바인딩이라고 부름 )

Dependency

의존성 종류

객체의 생명 주기 전체에 걸친 의존성
상속 (extends) => 부모가 변하면 모든 자식이 변한다 => 상속은 크리티컬하다.
연관 (association) => 필드에 그 객체타입을 알고 있음
각 오퍼레이션 실행 시 임시적인 의존성
의존(dependency)
상속 -> 연관 ( 상속을 소유모델로 변경 ) 연관 -> 의존 ( 연산을 통해 해결 => 함수로 이용하라 => 객체지향 깨지지만 여기로 가서 의존성을 약화 할 수도 있음 )

DI

어떠한 경우에도 다운캐스팅은 금지 폴리모피즘 (추상인터페이스) 사용
const Worker = class { run(){ console.log('working') } print(){ this.run() // 내적 일관성 ( internal identity ) } } const HardWorker = class extends Worker { run() { console.log('hardworking') } } const Manager = class{ #workers; constructor(...workers) { // OCP // 의존성을 구상클래스 HardWorker가 아닌 추상클래스인 Worker가 가지고 있음 // 때문에 확장가능함 if(workers.every(w=>w instanceof Worker)) this.#workers = workers; else throw "invalid workers"; } doWork() { this.#workers.forEach(w=>w.run()) } }; const manager = new Manager(new Worker(), new HardWorker()); manager.doWork();
JavaScript
복사

Inversion of Control

제어역전의 개념과 필요성

개념
1.
Control = flow control(흐름 제어)
2.
광의에서 흐름 제어 = 프로그램 실행 통제
3.
동기흐름제어, 비동기 흐름제어 등
⇒ 제어를 다른 곳에 위임한다.
문제점
1.
흐름 제어는 상태와 결합하여 진행됨
2.
상태 통제와 흐름제어 = 알고리즘
3.
변화에 취약하고 구현하기 어려움
대안
1.
제어를 추상화하고
2.
개별 제어의 차이점만 외부에서 주입받는다.
const Renderer = class { #view = null; #base = null; constructor(baseElement) { this.#base = baseElement; } set view(v) { if(v instanceof View) this.#view = v; else throw `invalid view: ${v}` } render(data) { // View의 제어는 renderer가 한다. const base = this.#base, view = this.#view if(!base || !view) throw 'no base or view'; let target = base.firstElementChild; do base.removeChild(target); while(target = target.nextElementSibling); base.appendChild(view.getElement(data)); view.initAni(); view.startAni(); } } const View = class{ getElement(data) { throw 'override!' } initAni(){throw 'override!' } startAni() { throw 'override!' } } const renderer = new Renderer(document.body) renderer.view = new class extends View{ #el; getElement(data){ this.#el = document.createElement("div"); this.#el.innerHTML = `<h2>${data.title}</h2><p>${data.description}</p>`; this.#el.style.cssText = "`width:100%; background:${data.background}`"; return this.#el } initAni(){ const style = this.#el.style; style.marginLeft = "100%"; style.transition = "all 0.3s"; } startAni(){ requestAnimationFrame(_=>this.#el.style.marginLeft = 0); } } renderer.render({title:'title test', description:'contents....', background:'#ffffaa'})
JavaScript
복사

제어역전 실제 구현

전략 패턴 & 템플릿 메소드 패턴 < 컴포지트 패턴 < 비지터 패턴 보다 넓은 범위의 제어 역전을 실현함
추상팩토리메서드 패턴 왼쪽 패턴은 이미 만들어진 객체의 행위를 제어역전에 참여시킬 수 있지만 참여할 객체 자체를 생성할 수 없음 참여할 객체를 상황에 맞게 생성하고 행위까지 위임하기 위해 추상팩토리 메소드를 사용함