관리 메뉴

효습

1.1 디자인 패턴 본문

CS

1.1 디자인 패턴

효효효효 2024. 8. 20. 00:56

디자인 패턴이란 프로그램을 설계할 때 , 발생했던 문제점들을 객체 간의 상호 관계 등을 이용하여

해결할 수 있도록 하는 규약 형태로 만들어놓은 것을 의미

1.1.1 싱글톤 패턴

싱글톤 패턴(singleton pattern) : 하나의 클래스에 오직 하나의 인스턴스만 가지는 패턴

  • 하나의 클래스를 기반으로 단 하나의 인스턴스를 만들어 이를 기반으로 로직을 만드는데 쓰며 , 보통 데이터베이스 연결 모듈에 많이 사용한다.
  • 장점 : 하나의 인스턴스를 만들어 놓고 해당 인스턴스를 다른 모듈들이 공유하면서 사용하기 때문에 인스턴스를 생성할 때 드는 비용이 줄어든다.
  • 단점 : 의존성이 높아짐. 멀티 스레드 환경에서 동기화 처리를 하지 않았을 때, 인스턴스가 2개가 생성되는 문제도 발생할 수 있다.
const URL = 'mongodb://localhost:8000/hj'
const createConnection = url =>({"url":url})
class DB {
     constructor(url){
        if(!DB.instance){
            DB.instance = createConnection(url)
         }
         return DB.instance
      }
      connect(){
          return this.instance
      }
}
const a = new DB(URL)
const b = new DB(URL)
console.log(a === b) //true
  • DB.instance라는 하나의 인스턴스를 기반으로 a , b 를 생성함

 

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class DatabaseConnection {
    // 싱글톤 인스턴스를 담을 정적 변수
    private static DatabaseConnection instance;
    private Connection connection;
    private String url = "jdbc:mysql://localhost:3306/yourdatabase"; // 데이터베이스 URL
    private String username = "yourusername"; // 사용자 이름
    private String password = "yourpassword"; // 비밀번호

    // 생성자는 private으로 설정하여 외부에서 인스턴스를 생성하지 못하게 함
    private DatabaseConnection() throws SQLException {
        try {
            // JDBC 드라이버 로드
            Class.forName("com.mysql.cj.jdbc.Driver");
            // 데이터베이스 연결 생성
            this.connection = DriverManager.getConnection(url, username, password);
        } catch (ClassNotFoundException ex) {
            ex.printStackTrace();
            throw new SQLException("DB Driver not found!", ex);
        }
    }

    // 싱글톤 인스턴스를 반환하는 정적 메서드
    public static DatabaseConnection getInstance() throws SQLException {
        if (instance == null) {
            // 인스턴스가 없으면 새로 생성
            instance = new DatabaseConnection();
        } else if (instance.getConnection().isClosed()) {
            // 기존 인스턴스의 연결이 닫혀있다면 새로 생성
            instance = new DatabaseConnection();
        }
        return instance;
    }

    // 데이터베이스 연결을 반환하는 메서드
    public Connection getConnection() {
        return connection;
    }
}
  • 이미 데이터베이스 연결 인스턴스가 존재한다면 인스턴스를 재사용함

 

싱글톤 패턴 단점

  • 싱글톤 패턴은 TDD(Test Driven Development)를 적용할 때 적합하지 않다.
  • TDD를 할 때, 단위테스트를 주로 하는데 단위테스트는 서로 독립적이어야하 하며 테스트를 어떤 순서로든 실행할 수 있어야 한다.
  • 하지만 싱글톤 패턴은 미리 생성된 하나의 인스턴스를 기반으로 구현하는 패턴이므로 각 테스트마다 독립적인 인스턴스를 만들기 쉽지 않다.

의존성 주입

  • 싱글톤 패턴은 굉장히 실용적이지만 모듈 간의 결합을 강하게 만든다는 단점이 있음

  • 이때 의존성 주입(DI , Dependency Injection)을 통해 모듈 간의 결합을 조금 더 느슨하게 만들 수 있다.
    • 의존성은 종속성이라고 하며 A가 B에 의존성이 있다는 것은 B의 변경 사항에 대해 A 또한 변경해야한다는 것을 의미
  • 메인 모듈이 직접 다른 하위 모듈에 대한 의존성을 주기보다는 중간에 의존성 주입자(dependency injection)가 이 부분을 가로채 메인 모듈이 간접 적으로 의존성을 주입하는 방법
    • 메인 모듈은 하위 모듈에 대한 의존성이 떨어지게됨 : 디커플링이 됨
  • 장점
    • 모듈들을 쉽게 교체할 수 있는 구조가 되어 테스팅하기 쉽고 마이그레이션하기도 수월하다.
    • 구현할 때 추상화 레이어를 넣고 이를 기반으로 구현체를 넣어 주기 때문에 애플리케이션 의존성 방향이 일관되고 , 애플리케이션을 쉽게 추론할 수 있으며 . 모듈 간의 관계들이 조금 더 명확해진다.
  • 단점
    • 모듈들이 더욱더 분리되므로 클래스 수가 늘어나 복잡성이 증가할 수 있다.
    • 약간의 런타임 패널티가 생기기도 한다.
  • 의존성 주입 원칙
    • 상위 모듈은 하위 모듈에서 어떠한 것도 가져오지 않아야 한다,
    • 둘 다 추상화에 의존해야 하며 , 이때 추상화는 세부 사항에 의존하지 말아야 한다.

 

1.1.2 팩토리 패턴

  • 팩토리 패턴(Factory pattern) 은 객체를 사용하는 코드에서 객체 생성 부분을 떼어내 추상화한 패턴
  • 상속 관계에 있는 두 클래스에서 상위 클래스중요한 뼈대를 결정
  • 하위 클래스에서 객체 생성에 관한 구체적인 내용을 결정하는 패턴
  • 상위 클래스와 하위 클래스가 분리되기 때문에 느슨한 결합을 가짐
  • 상위 클래스에서는 인스턴스 생성 방식에 대해 전혀 알 필요가 없기 때문에 더 많은 유연성을 가짐
  • 객체 생성 로직이 따로 떼어져 있기 때문에 코드를 리팩터링 하더라도 한 곳만 고치면 됨 → 유지 보수성 증가

 

 

1.1.3 전략 패턴

  • 전략 패턴(strategy pattern)은 정책 패턴(policy pattern)이라고도 한다.
  • 객체의 행위를 바꾸고 싶은 경우 ‘직접’ 수정하지 않고 ‘전략’이라고 부르는 캡슐화한 알고리즘을 컨텍스트 안에서 바꿔주면서 상호 교체가 가능하게 만드는 패턴
  • 예를 들어 결제를 할 때 네이버페이로 결제하는 방법이 있고 카카오페이로 결제하는 방법이 있듯이

컨텍스트 - 프로그래밍에서 컨텍스트는 상황, 맥락 , 문맥을 의미하며 개발자가 어떠한 작업을 완료하는 데 필요한 모든 관련 정보

passport의 전략 패턴

  • 전략패턴을 활용한 라이브러리
  • 서비스 내에서 인증된 회원을 관리하는 방식들로 다양한 ‘전략’을 지원함

 

1.1.4 옵저버 패턴

  • 옵저버 패턴(observer pattern)은 주체가 어떤 객체(subject)의 상태 변화를 관찰하다가 상태 변화가 있을 때마다 메서드 등을 통해 옵저버 목록에 있는 옵저버들에게 변화를 알려주는 패턴

  • 주체는 객체의 상태 변화를 보고 있는 관찰자
  • 옵저버들은 객체의 상태 변화에 따라 전달되는 메서드 등을 기반으로 추가 변화 사항이 생기는 객체들

 

  • 따로 관찰자를 두지 않고 상태가 변경되는 객체를 기반으로 구축하기도 함

  • 주로 이벤트 기반 시스템에 사용
  • MVC(Model- View-Controller) 패턴에도 사용
  • Model이 주체 , model에 변경사항이 생겨 update 메서드로 옵저버인 뷰에 알려줌 → 이를 기반으로 컨트롤러 작동

 

 

자바 : 상속과 구현

  • 상속(extends)
    • 자식 클래스가 부모 클래스의 메서드 등을 상속받아 사용하며 자식 클래스에서 추가 및 확장을 할 수 있음
    • 재사용성 , 중복성의 최소화
  • 구현(implements)
    • 부모 인터페이스(interface)를 자식 클래스에서 재정의하여 구현
    • 상속과 달리 반드시 부모 클래스의 메서드를 재정의하여 구현해야 함
  • 상속은 일반 클래스 , abstract(추상)클래스를 기반으로 구현하며 , 구현은 인터페이스를 기반으로 구현

 

자바스크립트에서 옵저버 패턴

프록시 객체

  • 프록시(proxy)객체는 어떠한 대상의 기본적인 동작(속성 접근 , 할당 , 순회 , 열거 , 함수 호출 등)의 작업을 가로챌 수 있는 객체를 뜻함
  • 자바스크립트에서 프록시 객체는 target(프록시할 대상) , handler(target의 동작을 가로채고 어떠한 동작을 할 것인지 설정되어 있는 함수) , 2가지 매개변수를 가진다.

 

 

1.1.5 프록시 패턴과 프록시 서버

프록시 패턴 안에 프록시 객체가 있음

프록시 패턴

  • 프록시 패턴(proxy patter)은 대상 객체(subject)에 접근하기 전 그 접근에 대한 흐름을 가로채 필터링하거나 수정하는 등의 역할을 하는 계층이 있는 디자인 패턴
  • 객체의 속성 , 변환 등을 보완하며 보안 , 데이터 검증 , 캐싱 , 로깅에 사용

프록시 서버

  • 프록시 서버는 서버와 클라이언트 사이에서 클라이언트가 자신을 통해 다른 네트워크 서비스에 간접적으로 접속할 수 있게 해주는 컴퓨터 시스템이나 응용 프로그램을 뜻함

  • nginx
    • 비동기 이벤트 기반의 구조와 다수의 연결을 효과적으로 처리 가능한 웹서버
    • 주로 Node.js 서버 앞단의 프록시 서버로 활용
    • 익명 사용자가 직접적으로 서버에 접근하는 것을 차단하고 ,
    • 간접적으로 한 단계를 더 거치게 만듦 → 보안 강화
    • 실제 서버 포트를 숨길수도 있고
    • 정적 자원을 압축하거나
    • 메인 서버 앞단에서의 로깅을 할 수 있음
  • 프록시 서버로 쓰이는 CloudFlare
    • CDN 서비스
    • 웹 서버 앞단에 프록시 서버로 두어 DDOS 공격 방어나 HTTPS 구축에 쓰임
    • 의심스러운 트래픽이 발생하면 먼저 판단하여 일정 부분 막아주는 역할도 수행
    • DDOS 공격 방어
      • 짧은 기간 동안 네트워크에 많은 요청을 보내 네트워크를 마비시켜 웹 사이트의 가용성을 방해하는 사이버 공격
      • CloudFlare의 거대한 네트워크 용량과 캐싱 전략으로 소규모 DDOS 공격은 쉽게 막아낼 수 있음
      • 공격에 대한 방화벽 대시보드 제공
    • HTTPS 구축
      • 서버에서 HTTPS를 구축할 때 , 인증서를 기반으로 할 수 있지만
      • CloudFlare를 사용하면 별도의 인증서 없이 HTTPS를 구축할 수 있음
    • CDN(Content Delivery Network)
      • 각 사용자가 인터넷에 접속하는 곳과 가까운 곳에서 콘텐츠를 캐싱 또는 배포하는 서버 네트워크
      • AWS CloudFront

CORS와 프론트 엔드의 프록시 서버

  • CORS(Cross-Origin Resource Sharing)는 서버가 웹 브라우저에서 리소스를 로드할 때 , 다른 오리진을 통해 로드하지 못하게 하는 HTTP헤더 기반 매커니즘
  • 이를 해결하기 위해 프런트엔드에서 프록시 서버를 만들기도 함

1.1.6 이터레이터 패턴

  • 이터레이터 패턴(iterator pattern)은 이터레이터(iterator)를 사용하여 컬렉션(collection)의 요소들에 접근하는 디자인 패턴
  • 순회할 수 있는 여러 가지 자료형의 구조와는 상관없이 이터레이터라는 하나의 인터페이스로 순회 가능

1.1.7 노출모듈 패턴

  • 노출모듈 패턴(revealing module pattern)은 즉시 실행 함수를 통해 private , public 같은 접근 제어자를 만드는 패턴
  • 자바스크립트는 private나 public 같은 접근 제어자가 존재하지 않아 노출모듈 패턴을 통해 pirvate와 public 접근 제어자를 구현하기도 함

 

 

1.1.8 MVC 패턴

  • 모델(Model), 뷰(View) , 컨트롤러(Controller)로 이루어진 디자인 패턴
    • 본질적인 목표는 관심사를 분리

  • 애플리케이션의 구성 요소를 세 가지 역할로 구분하여 각 요소에 집중하여 개발할 수 있음
  • 재사용성과 확장성이 용이하다는 장점
  • 애플리케이션이 복잡해질수록 모델과 뷰의 관계가 복잡해짐
  • 모델(Model)
    • 애플리케이션의 데이터인 데이터베이스 , 상수 , 변수 등을 뜻함
    • 뷰에서 데이터를 생성하거나 수정하면 컨트롤러를 통해 모델을 생성하거나 갱신함
  • 뷰(View)
    • 사용자 인터페이스 요소를 나타냄
    • 모델을 기반으로 사용자가 볼 수 있는 화면
    • 모델이 가지고 있는 정보를 따로 저장하지 않아야 하며 화면에 표시하는 정보만 가지고 있어야 함
    • 변경이 일어나면 컨트롤러에 이를 전달해야함
  • 컨트롤러(Controller)
    • 하나 이상의 모델과 하나 이상의 뷰를 잇는 다리 역할
    • 이벤트 등 메인 로직을 담당
    • 모델과 뷰의 생명주기도 관리
    • 모델이나 뷰의 변경 통지를 받으면 이를 해석하여 각각의 구성 요소에 해당 내용에 대해 알려줌
  • 장점
    • 컴포넌트의 명확한 역할 분리로 인해 서로 간의 결합도를 낮출 수 있다.
    • 코드의 재사용성 및 확장성을 높일 수 있다.
    • 서비스를 유지보수하고 테스트하는데 용이해진다.
    • 개발자 간의 커뮤니케이션 효율성을 높일 수 있다.
  • 예시
    • 사용자의 request(요청)을 Controller가 받는다
    • Controller는 Service에서 비즈니스 로직을 처리한 후 결과를 Model에 담는다.(Spring에서는 Dto가 이 역할을 함)
    • Model에 저장된 결과를 바탕으로 시각적 요소 출력을 담당하는 View를 제어하여 사용자에게 전달(프론트가 api의 응답으로 화면을 구성함)
  • 대표적인 예 : Spring
    • @RequestParam , RequestHeader , @PathVariable 와 같은 애너테이션을 기반으로 사용자의 요청 값들을 쉽게 분석하며 어떠한 요청이 유효한 요청인지를 쉽게 거를 수 있음

 

MVC 규칙을 지키면서 코딩하는 법

  • 모델은 컨트롤러나 뷰에 의존하면 안된다.
    • 모델 내부에 컨트롤러 및 뷰와 관련된 코드가 있으면 안된다.
  • 뷰는 모델에만 의존해야 하고 , 컨트롤러에 의존하면 안된다.
    • 뷰 내부에 모델의 코드만 있을 수 있고 , 컨트롤러의 코드가 있으면 안된다.
  • 뷰가 모델로부터 데이터를 받을 때는 사용자마다 다르게 보여주어야 하는 데이터에 한해서만 받아야 한다.
  • 컨트롤러는 모델과 뷰에 의존해도 된다.
    • 컨트롤러 내부에는 모델과 뷰의 코드가 있을 수 있다.
  • 뷰가 모델로부터 데이터를 받을 때는 반드시 컨트롤러에서 받아야 한다.

 

 

MVC 패턴의 한계점

  • Model과 View의 의존성을 완전히 분리시킬 수 없다
  • 컨트롤러의 비중이 높아져 부담이 커진다면 Massive-View-Controller 현상을 피할 수 없다

이러한 MVC 패턴의 문제를 해결하기 위한 대안으로 MVP , MVVM이 있음

 

 

1.1.9 MVP 패턴

  • MVC 패턴으로부터 파생
  • 컨트롤러 → 프레젠터로 교체된 패턴
  • MVC 패턴의 컨트롤러와 다르게 프레젠터는 View와 작접 연결되지 않고 사용자 인터페이스를 통해 상호작용함
  • 동작 순서
    • 사용자의 요청은 View를 통해 받게 됨
    • View는 데이터를 Presenter에 요청한다.
    • Presenter는 Model에게 데이터를 요청
    • Model은 요청을 통해 비즈니스 로직을 수행하여 Presenter에서 요청받은 데이터를 전달
    • Presenter는 View에게 전달받은 데이터를 응답
    • View는 Presenter가 응답한 데이터를 이용하여 화면을 출력
  • Presenter를 통해서만 데이터를 전달받기 때문에 MVC 패턴에서 발생하는 View와 Model의 의존성을 제거할 수 있지만 View와 Presenter의 의존성이 높아짐

 

 

1.1.10 MVVM 패턴

  • 컨트롤러 → 뷰모델로 교체
  • 뷰모델(View Model)은 뷰를 더 추상화한 계층
    • 뷰모델이 view와 model 사이에서의 중개자 역할을 수행하며 , View를 보여주기 위한 데이터 처리 역할을 수행하는 요소. 즉, View를 표현하기 위해 만들어진 Model임
  • 동작 순서
    • 사용자의 요청은 View를 통해 받음
    • View에서 요청을 받는다면 , Command 패턴으로 View Model로 요청을 전달
    • View Model은 Model에게 요청 처리에 필요한 데이터를 요청
    • Model은 내부적으로 비즈니스 로직을 수행하여 View Model에게 필요한 데이터 전달
    • View Model은 전달받은 데이터를 가공하여 저장
    • View는 View Model과 Data Binding하여 사용자에게 요청에 적절한 화면 출력
  • MVC 패턴과는 다르게 커맨드와 데이터바인딩을 가지는 것이 특징
    • 커맨드 : 여러 가지 요소에 대한 처리를 하나의 액션으로 처리할 수 있게 하는 기법
    • 데이터 바인딩 : 화면에 보이는 데이터와 웹 브라우저의 메모리 데이터를 일치시키는 기법 , 뷰모델을 변경하면 뷰가 변경됨
  • 뷰와 뷰모델 사이의 양방향 데이터 바인딩을 지원함
  • MVC 패턴에서 발생하는 View와 Model의 의존성 문제는 해결할 수 있으나 ViewModel을 설계하는 과정이 복잡하고 어려움
  • UI를 별도의 코드 수정 없이 재사용할 수 있고 단위 테스트하기 쉬움
  • 대표적인 예 : Vue.js

 

 

참고 

https://velog.io/@langoustine/%EC%97%AC%EA%B8%B0%EB%8F%84-MVC-%EC%A0%80%EA%B8%B0%EB%8F%84-MVC-MVC-%ED%8C%A8%ED%84%B4%EC%9D%B4-%EB%AD%90%EC%95%BC

 

여기도 MVC, 저기도 MVC! MVC 패턴이 뭐야?

어딜가든 MVC에 대해서 많이 듣고 접하게 되는데 과연 MVC 패턴은 무엇이고 왜 등장했는지, 더 나아가 MVC의 필요성과 한계점은 무엇인지 학습하고 고민한 내용을 기록하였습니다.

velog.io

 

'CS' 카테고리의 다른 글

3.4 CPU 스케쥴링 알고리즘  (1) 2024.09.26
2.3 네트워크 기기  (0) 2024.09.04
2.2 TCP/IP 4계층 모델  (0) 2024.08.27
2.1 네트워크 기초  (0) 2024.08.27
1-2. 프로그래밍 패러다임  (0) 2024.08.27