디자인 패턴과 프로그래밍 패러다임

minjeong·2023년 1월 9일
0

디자인 패턴

싱글톤 패턴(Singleton Pattern)

class Database {
  const URL = '...';
  
  constructor() {
    if (!Database.instance) {
      Database.instance = createConnection(URL);
    }
    return Database.instance;
  }

  connect() {
    return this.instance;
  }
}
  • 하나의 클래스에 오직 하나의 인스턴스를 가진다.
  • 데이터베이스 연결 모듈에 많이 사용한다.
  • 인스턴스를 생성하고 관리하는 비용이 줄어들지만, 의존성이 높아진다는 단점이 있다.

의존성 주입(DI, Dependency Injection)

  • 사용이 쉽고 실용적이지만 모듈 간의 결합이 강해진다 -> 의존성이 강해진다.
  • 의존성 주입이란, 메인 모듈이 '직접' 하위 모듈에 대한 의존성을 갖는 대신 의존성을 주입시켜 객체들 간의 상호작용을 최소한으로 시킨다. 즉, 메인 모듈이 간접적으로 의존성을 갖도록 모듈 간의 결합을 느슨하게 한다. -> 의존성을 낮춘다.


▲ 출처 https://devopedia.org/dependency-injection

  • "상위 모듈은 하위 모듈에서 어떠한 것도 가져오지 않아야 한다."

  • 모듈을 쉽게 교체할 수 있는 구조가 되어 테스트가 쉽고 마이그레이션에도 수월하다.

  • 추상화 레이어를 넣고 구현체를 넣어주기 때문에 애플리케이션의 의존성 방향이 일관되고, 모듈 간 관계가 명확해진다.

  • 참고하기

팩토리 패턴(Factory Pattern)

// before
let coffee1 = new Latte();
let coffee2 = new Espresso();

// after
let coffee1 = CoffeeFactory.brew('Latte');
let coffee2 = CoffeeFactory.brew('Espresso');
// before
class Latte extends Coffee {
  constructor() {
    this.name = 'Latte';
  }
}

// after
class Latte extends Coffee {
  constructor() {
    this.name = 'Latte';
  }
}

class LatteFactory {
  static brew() {
  	return new Latte();
  }
}

class CoffeeFactory {
  constructor() {
  	this.factories = { 'Latte': LatteFactory } //...
  }
  
  static brew(type) {
    const factory = this.factories[type];
    return factory.brew();
  }
}
  • 개체 생성 부분의 추상화.
  • 클래스의 인스턴트를 생성하는 주체는 객체 생성 로직을 전혀 알지 않아도 생성할 수 있으므로 유연성을 갖게 되고 유지 보수성이 좋아진다.
  • 팩토리 클래스에서 정적(static) 메서드로 정의할 경우 클래스의 인스턴스를 만들지 않고도 호출이 가능하므로 메모리를 절약할 수 있다.

전략 패턴(Strategy Pattern)

  • 정책 패턴(Policy Pattern)이라고도 한다.
  • 객체의 행위를 바꾸고 싶을 때 '직접' 수정하지 않고 전략이라고 부르는 '캡슐화한 알고리즘'을 컨텍스트 안에서 바꿔주며 상호 교체가 가능하도록 한다.

읽어보기 https://refactoring.guru/ko/design-patterns/strategy
읽어보기 https://developercc.tistory.com/18

옵저버 패턴

  • publish/subscribe 개념으로 설명하기도 한다.
  • 주체가 어떤 객체(Subject)의 상태 변화를 관찰하다가 상태 변화가 있을 때마다 구독 모델(Observer)에게 변화를 알려준다. (객체와 주체가 합쳐진 패턴도 흔히 쓰인다.)
  • 1:n 의존성.
  • 이벤트 기반 시스템에 사용한다.
  • 예시
    • 객체: 상태 변화가 일어나는 관심 대상 -> 유튜버
    • 구독 모델(옵저버): 객체의 상태 변화를 보고 있는 관찰자 -> 유튜브 구독자들

읽어보기 https://coding-factory.tistory.com/710

프록시 패턴

  • 프록시 객체가 대상 객체에 접근하기 전 그 접근에 대한 흐름을 가로채 대산 객체 앞단의 인터페이스 역할을 수행한다.

프록시 서버

  • 서버와 클라이언트 사이에서 클라이언트가 프록시 서버를 통해 네트워크 서비스에 간접적으로 접속할 수 있게 해준다.
  • 클라이언트의 속성, 변환 등을 보완하며 보안, 데이터 검증, 캐싱, 로깅 등에 사용한다.

읽어보기 Proxy vs. VPN

이터레이터 패턴

  • 이터레이터를 사용해 컬렉션의 요소에 접근한다.
  • 다른 자료구조임에도 for (let obj of collection)이라는 동일한 이터레이터 프로토콜을 통해 순회가 가능하다.

노출모듈 패턴

  • private/public 같은 접근 제어자를 만드는 패턴.
  • javascript는 접근 제어자가 존재하지 않고 스크립트가 전역 범위에서 실행된다.
  • javascript의 private class fields 문법: 변수나 메서드 앞에 #을 붙인다. 이렇게 하면 클래스 내부적으로는 접근 가능하나 외부에서는 setter/getter로 접근해야 한다.

출처 MDN - Private class features

MVC 패턴

  • Model: 애플리케이션의 데이터.

  • View: 사용자 인터페이스 요소. 모델을 기반으로 사용자가 볼 수 있는 화면.

  • Contoller: 메인 로직. 이벤트 처리, 보델과 뷰의 생명주기 관리 등의 기능 수행.

  • 애플리케이션의 구성 요소를 세 역할로 분리하여 개발한다. 재사용성과 확장성이 용이하지만, 애플리케이션이 복잡해질수록 Model <-> View 관계가 복잡해진다 = View와 Model 사이의 의존성이 높아진다.

    	View   --- event --->  Controller --- update ---> Model
    	Model  --- notify ---> Controller --- update ---> View

MVP 패턴

  • Contoller: 메인 로직. 이벤트 처리, 보델과 뷰의 생명주기 관리 등의 기능 수행.

  • MVC 패턴으로부터 파생되어 Contoller가 Presenter로 교체.

  • 인터페이스로 통신하여 MVC 패턴의 View와 Model 사이의 의존성을 없내는 것이 목적이다. 그러나 다시 View와 Presenter 사이의 의존성이 커진다는 단점이 있다.

    	View --- getData() ---> Present --- getData() ---> Model
    	     <-- ui data <----- Present <-- data ------------┛

MVVM 패턴

읽어보기 MVC, MVP, MVVM
읽어보기 MVC, MVP, MVVM
읽어보기 MVC, MVP, MVVM in Angular

프로그래밍 패러다임

선언형 프로그래밍(Declarative Programming)

  • '무엇을' 풀어내는가에 집중하는 패러다임.
  • "프로그램은 함수로 이루어진 것이다." 라는 명제가 담겨 있는 패러다임.

함수형 프로그래밍(Functional Programming)

  • 작은 '순수 함수'들을 사용하여 로직을 구현하고 '고차 함수'를 통해 재사용성을 높인다.

  • javascript는 단순하고 유연한 언어적 특성을 가지면서 함수가 일급 객체이기 때문에, 객체지향 프로그래밍보다는 함수현 프로그래밍 방식이 선호된다.

  • 순수 함수

    • 출력이 입력에만 의존한다.
  • 고차 함수

    • 함수가 함수를 값처럼 매개변수로 받아 로직을 생성할 수 있다.
    • 일급 객체인 언어여야 가능하다.
    • 일급 객체
      • 변수나 메서드에 함수를 할당할 수 있다.
      • 함수 안에 함수를 매개변수로 담을 수 있다.
      • 함수가 함수를 반환할 수 있다.

명령형 프로그래밍(Imperative Programming)

객체 지향 프로그래밍(OOP, Object-Oriented Programming)

  • 프로그램의 상호 작용을 객체들의 집합과 관계로 표현한다.
  • 데이터를 객체로 취급하여 객체 내부에 선언된 메서드를 활용한다.
  • SOLID 설계 원칙
  • 특징
    • 추상화(Abstraction)
      • 복잡한 시스템으로부터 핵심적인 개념, 기능 간추리는 것.
      • class Dog, Cat, Bird => Animal
    • 캡술화(Encapsulation)
      • 객체의 속성과 메서드를 하나로 묶고 일부를 외부에 감추어 은닉하는 것.
    • 상속성(Inheritance)
      • 상위 클래스의 특성을 하위 클래스가 이어받아 재사용, 확장하는 것.
      • class Bus, Subway, Srt extends PublicTransport
    • 다형성(Polymorphism)
      • 하나의 메서드나 클래스가 다양한 방법으로 동작하는 것.
      • 오버로딩(Overloading): 같은 이름을 가진 메서드를 여러 개 두는 것. 메서드의 return type, parameter의 개수 및 type 등의 차이로 구분할 수 있다. javascript에서는 직접 제공하는 기능은 아니지만 arguments.length 값으로 분기 처리하여 동작하게 할 수 있다고 한다.
      • 오버라이딩(Overriding): 상위 클래스로부터 상속받은 메서드를 하위 클래스에서 재정의하는 것.

절차 지향 프로그래밍

  • 로직이 수행되어야 할 연속적인 계산 과정으로 이루어져 있다.
  • 일이 진행되는 방식으로 코드를 구현하므로 코드의 가독성이 좋고 실행 속도가 빠르다.
  • 그러나 모듈화하기 어렵고 유지 보수성이 떨어진다는 단점을 갖는다.

출처《면접을 위한 CS 전공지식 노트》, 16-66p

profile
프론트엔드 개발자 👩‍💻

0개의 댓글