[코드스피츠] 객체지향1

sangeun·2020년 2월 2일
0

코드스피츠

목록 보기
3/3

함수지향 vs 객체지향

함수지향

  • 끝없는 복사본
  • 상태 변화에 안전: 계속 복사하니 기존의 값은 안전함. 3 + 1을 한다면 새로 연산된 4는 불변성을 통해서 안전하지만, 예전의 3의 문제가 해결되는 것도 아니고 3과 1은 그대로 존재한다. 안전하게 상태를 보관했다고 보기는 어려움.
  • 연산을 기반으로 로직을 전개

객체지향

  • 하나의 원본: 값이 mutable함
  • 상태 변화를 내부에서 책임짐: 이게 매우 어려운 점
  • 메세지를 기반으로 로직을 전개

polymophism(다형성)

다형성이 갖춰지면 객체지향 언어라고 할 수 있다.

대체가능성(substitution): 확장된 객체는 원본으로 대체 가능
내적일관성(internal identy): 어때한 경우에도 태어났을 때의 원본 클래스를 유지하려고하는 속성(생성 시점의 타입이 내부에 일관성 있게 참조됨)

자바스크립트에서 내적일관성 구현방식

프로토타입 체인

worker hardworker class(function)
proto --> hardworker prototype (constructor(함수의 프로토타입이므로 가지게 됨, 자기 자신을 가리키고 있음), proto(객체이므로 얘도 가짐), 클래스의 메소드들)

즉,

class HardWorker extends Worker
const worker = new HardWorker();

에서 worker은 proto를 가지는데, 이는 자신의 원본인 hardworker의 프로토타입을 가리킨다. hardworker의 프로토타입 또한 객체이므로 proto를 가지고, 함수(function)의 프로토타입이므로 constructor을 가진다. 이는 자기 자신을 가리키고 있다. HardWorker은 Worker을 상속받았으므로, proto는 Worker의 프로토타입을 가리킨다.

따라서 프로토타입 체이닝이란, 해당 객체의 proto를 확인해서 원본의 프로토타입을 확인하고, 그 원본의 proto를 확인하는 방식을 반복하며 진행된다. 이를 통해 constructor로 직접 원본을 확인하거나, 원본이 가진 메서드를 확인해 대체가능성과 내적일관성을 구현할 수 있다.

구현방법

먼저 그 객체의 메서드들에서 존재하는지 확인하고, 그 다음 proto를 통해 부모를 확인하고 계속해서 위로 올라가며 메서드가 존재하는지 확인한다. 따라서 부모와 자식이 같은 함수를 가지고 있을 경우, 자식의 메서드가 호출되는 것이다.

자바스크립트에서 대체가능성 구현방식

A instanceof B 일 경우, 객체 A의 proto를 확인하면, 원본의 constructor을 알 수 있으므로, B의 constructor와 이가 같은지 확인한다. 같지 않을 경우에는 프로토타입 체이닝을 통해 부모의 constructor을 확인한다.

객체지향에 맞는 객체

요건

  • 은닉: 모든 데이터는 private이어야 한다. 상태를 외부에 보여주지 않으려면 private이 필수이다. 이렇게 되면 객체가 값으로 사용되는 일이 많아지게 되고, 객체지향이 아니게 된다.
  • 캡슐화: 은닉이 변수에 대한 것이라면, 캡슐화는 메서드에 대한 것이다.(구체적인 메서드가 아니라 추상적인 메서드를 만들어야 한다.) setter와 getter로 private변수를 사용하면 제대로 된 캠슐화가 이뤄지지 않은 것이다.
    ex) setAge를 피하는 방법
    age필드를 그대로 노출 -> setAge를 왜 하는 것인가? -> 어디에 왜 쓰는지 생각해보아야 한다. -> 나이에 따라서 컨텐츠를 구분할려고 하는 것이다 -> setAdult, setChild로 추상화해야 외부에서 내 상태를 관리하지 않고 내부에서 내 상태를 관리할 수 있다.

이유

변화에 대한 격리를 위해

SOLID원칙

  • SPR: 단일 책임 원칙(이 코드를 고쳐야 하는 이유는 하나뿐인 것, 이를 지키지 못하면 shotgun surgery(산탄총 수술)이 일어난다.)
  • OCP: 개방 폐쇄 원칙(extends나 implements를 하게 만들고, 기존에 있는 것들은 수정하지 않도록 만드는 것)
  • 리스코프 치환 원칙: 추상층의 정의가 너무 구체적이면 구상층의 구현에서 모순이 발생함. 업캐스팅이 안전해야 하는데 추상클래스 구현이 너무 구체적이면 구현이 안되는 경우를 막아야 함
  • ISP(Interface Segergation): 인터페이스 분리 (한 객체가 너무 비대해졌을 경우 소유를 사용하거나 위임을 사용하여 분리할 수 있다. 소유 방식은 사용처에 따라 객체를 하나씩 생성, 위임방식은 인터페이스를 구현한 메서드들을 오버라이드하기 때문에 인터페이스를 건드린다고 메서드에 영향이 가지 않는다.) ??????? 에바
  • DIP: 의존성 역전 법칙: 다운캐스팅금지(의존성은 부모쪽으로만 흘러가야 함, 만약 instanceof C일때.. 이런 코드가 들어가있으면 다운캐스팅을 하고 있는 것, 즉 자식쪽에 의존하고 있는 것이므로 코드를 잘못 짜고 있는 것이다.)

고차원의 모듈은 저차원의 모듈에 의존하면 안된다. 이 두 모듈 모두 추상화된 것에 의존해야 한다.????
DI: 의존성 주입
IOC: 제어 역전
DRY(Don't Repeat Yourself): 중복 방지
Hollywood Principle: 의존성 부패방지(부모클래스는 서브클래스에 정의된 연산에 대한 호출을 할 수 있지만 그 반대방향은 일어나면 안 된다. 이렇게 어떤 대상에게 질의를 하게 되면 은닉, 캡슐화를 잊게 된다)
Law of demeter: 어떠한 객체에 대해 최소한의 지식만 알아야 함, 의존성의 부패를 막기 위해

  • 최소한의 지식
    classA.methodA의 경우
    - classA의 필드 객체
    - methodA가 생성한 객체
    - methodA의 인자로 넘어온 객체

메세지

SRP

단일 책임 원칙을 준수하는 객체에게 그 이상의 업무를 부여하면

  • 만능 객체가 되려 한다
  • 다른 객체한테 의뢰한다.

다른 객체에게 의뢰하는 것 = 다른 객체에게 메세지를 보내는 것

  • 메세지: 의뢰할 내용
  • 오퍼레이션: 메세지를 수신할 객체가 제공하는 서비스
  • 메소드: 오퍼레이션이 연결될 실제 처리기
    오퍼레이션이 호출되면 그때에 따라 다른 메소드가 호출되는 것을 동적 바인딩이라고 한다.

오퍼레이션과 메소드를 분리해서 상황에 따라 원하는 메소드를 호출하기 위해 추상클래스나 인터페이스를 상속시킨다.(OCP)

의존성

의존성이 있으면 의존되는 관계에 있는 객체들의 영향을 그대로 받는다. => 격리성을 높여야
너무 의존성이 없으면 만능 객체가 태어나게 됨. 너무 의존성이 크면 한 객체가 수정되거나 추가되면 다른 객체들이 전부 영향을 가지게 된다. 따라서 적당한 의존성을 가져야 한다.

의존성 만드는 방법

객체의 생명 주기 전체에 걸친 의존성

  • 상속: 매우 강력해서 부모 객체가 바뀌면 수정될 것을 각오해야 한다.
    -> 연관: 필드에 객체를 저장해놓는 것.(소유)

각 오퍼레이션 실행 시 임시적인 의존성
-> 의존: 오퍼레이션 실행 시에만 연결이 되고, 메서드 호출이 되면 의존성이 생기고 호출이 끝나면 의존성이 사라지는 약한 의존성을 가진다.

연관에서 의존으로 바꾸기 위해서는 상태를 저장해놓는 방식을 포기해야 한다. 그러면 함수형 아니냐, 따라서 쉽게 바꾸지 못함

높은 의존성 단점

  • 수정 여파 규모증가
  • 수정하기 어려운 구조 생성
  • 순환 의존성

의존성 역전

어떠한 경우에도 다운캐스팅은 금지하고 다형성 사용하는 것. DIP와 OCP는 깊은 연관을 가지고 있다. 부모쪽에 의존성을 가지면, 새로운 자식이 추가되어도 기존의 코드는 수정되지 않아 OCP가 이뤄진다고 볼 수 있기 때문이다.

profile
꾸준히

0개의 댓글