Notice
Recent Posts
Recent Comments
Link
«   2026/04   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30
Tags
more
Archives
Today
Total
관리 메뉴

일상

11주차 - Design Pattern 본문

교육

11주차 - Design Pattern

콜리/khgeung 2025. 7. 13. 22:17

1. Software Architecture

  • 소프트웨어 설계 양식 : 소프트웨어의 전체 구조를 표현하며 소프트웨어 구성요소(component) 사이의 관계를 정의한다.
    • 초기 웹 개발 방식 (1990년대 후반 ~ 2000년대 초반)
      • JSP <-> Database
    • Model 1 Architecture (2000년대 초반 ~ 중반)
      • JSP <-> java beans(Dao, Service 등) <-> Database
      • Model 1에서 java bean 은 java component 를 의미한다.
      • java bean 은 business logic 과 data access logic 을 담당한다.
      • Jsp는 요청을 분석하여 java bean 과 연동하는 역할과 응답을 전담하는 view 역할을 한다.
    • 이후
      • Model 2 Architecture (2000년대 초중반 ~ )

2. Model 1 Architecture

 

3. Model 2 Architecture

3-1. Model 2 Architecture 개요

  • View(Jsp), Controller(Servlet), Model(java beans)Model 2 MVC 또는 Web MVC 또는 MVC 2 라고 불린다.
    • Model : 데이터와 비즈니스 로직 담당
    • View : 응답 전담 (화면 표시 담당, Http Response Message 를 전담)
    • Controller : 요청 처리를 전담, Model 과 View 를 제어
      • 클라이언트의 요청을 분석
      • 분석 내용에 따른 Model 연동
      • 연동 결과를 View 와 공유하기 위한 작업
      • 제어 이동 방식 (forward or redirect)을 결정하여 응답을 위한 View로 이동
  • JSP가 View 역할을 담당하는 이유?
    • JSP는 Java Server Page, 동적인 웹  페이지 구현 및 응답 최적화 기술이다.
  • Servlet 이 왜 Controller 역할을 전담할까?
    • Http를 이해하는 Java 클래스가 HttpServlet class 이고, HttpServlet class 는 Http 프로토콜 기반의 프로그램 구현에 최적화 되어 있다. Http Request와 Http Response는 프로토콜 기반의 프로그램 구현에 최적화 되어 있어 Http Request와 Http Response Message 분석 후 제어하는 컨트롤러에 가장 최적화된 기술이다. (이로인해 Spring의 DispatcherServlet이 가장 중요한 Front Controller 로 되어 있다.
  • java component가 왜 model 역할을 할까? 
    • 비즈니스 로직과 데이터 액세스 로직을 처리하기 가장 최적화 되어 있기 때문이다.

3-2. Singleton Design Pattern

  • 시스템 상에서 단 한번 객체를 생성하고 공유해서 사용하는 디자인 패턴
  • Spring에서 기본적으로 객체를 운용(매니징)하는 방식
  • 서버 자원의 효율성 : 불필요하게 반복적으로 객체를 여러개 생성하지 않으므로 자원 절약
  • 실제로 Spring bean(자바 컴포넌트), Servlet이 컨테이너에 의해 싱글톤으로 매니징된다.

3-3. Controller 에서 View 로 제어를 이동하는 방식

  • forward 방식 
    • 웹 컨테이너 상에서 이동하는 방식으로, request와 response가 유지된다. (재 요청 시 재동작되는 특성을 지닌다.)
    • 정보 조회 용도에 적합하다.
  • redirect 방식 
    • 클라이언트에게 응답 View url을 지정하는 방식
    • 기존 요청에 대한 응답으로 새로운 페이지 url을 명시하여 결과를 보는 방식
    • 기존 request와 response 는 유지되지 않으므로, 재 동작이 되지 않아야 하는 작업에 적합하다. (회원 가입, 로그인, 상품 등록 등)
forward redirect
서버 내부에서 동작 클라이언트 브라우저가 동작
url 변경 X url 변경 O
요청 객체 유지 O 요청 객체 유지 X
웹 컨텍스트 경로를 제외한 내부 경로(/) 웹 컨텍스트 경로 포함 절대/상대 경로
중복 동작(or 재동작) 가능 중복 동작 방지용
브라우저에서는 단일 요청/응답으로 인식 재요청으로 인식

3-4. EL (Expression Language)

  • JSP 버전이 상향되면서 추가된 스크립트 언어로, 기존 Scrpitlet tag 의 표현식(<%= %>)의 업그레이드 된 버전( ${ })
  •  JSP 속성영역(request, session, application(ServletContext))에 저장된 객체의 property를 출력하는 용도이다.
  • EL을 이용하면 별도의 import, Object Casting 절차 필요 없이 바로 출력이 가능하다.
  • 다양한 연산 및 자동 형변환이 된다.
  • JSTL과 연동이 가능하다.
  • Model 객체의 get 계열 메소드와 is 계열의 메소드에 접근이 가능하다.

3-5. JSTL (Jsp Standard Tag Library) 

  • View(JSP)에서 자주 사용하는 기능으로, 조건문/반복문/자료구조의 데이터 표현을 미리 구현해놓은 태그 라이브러리이다.
  • EL과 함께 사용해서 View 로직과 데이터를 표현한다.
  • JSTL 라이브러리 구성 요소
    • jakarta.servlet.jsp.jstl-api-3.0.0.jar : JSTL 태그들의 인터페이스와 명세를 정의하는 API 라이브러리
    • jakarta.servlet.jsp.jstl-3.0.1.jar (또는 org.glassfish.web : jakarta.servlet.jsp.jstl) : JSTL API의 실제 구현체로, 태그들의 동작을 실제로 수행하는 구현 라이브러리
      • 개발 시 : API JAR 만 있어도 코드 작성과 컴파일 가능
      • 실행 시 : 구현 JAR 이 있어야 실제 태그 기능이 동작
      • => Java의 핵심 설계 원칙인 '인터페이스와 구현의 분리' 를 보여주는 예시
    • JSP 페이지에서 JSTL 사용 선언부
      • <%@ taglib prefix="c" uri="jakarta.tags.core" %>
      • tomcat 10.1은 Jakarta EE 10을 기반으로 하므로 jakarta.tags.core 네임스페이스를 사용해야 한다.

4. Model 2 Architecture - FrontController Design Pattern

4-1. Front Controller Design Pattern

  • 모든 클라이언트 요청을 하나의 진입점으로 통합하여 처리하는 패턴
  • 실생활의 예 : 호텔 프론트
    • 모든 고객 요청이 프론트 데스크로 집중
    • 프론트 데스크에서 요청에 대한 적절한 부서 또는 담당자로 연결
    • 체크인, 홈서비스, 청소 등 각각 전담 부서 처리
  • Front Controller 가 없다면?
    • 각 기능 마다 별도 입구를 찾아야 한다.
    • 공통 처리 로직 중복 (보안, 로깅, 인코딩 등)
    • 일관성 없는 처리 방식
    • 관리 포인트 급증
    • 생산성 저하 및 유지보수의 어려움
  • 해결책 : 모든 요청을 하나의 입구로 처리
    • 공통 로직의 중앙화
    • 일관된 요청 처리 흐름
    • 관리 포인트 단일화
    • 확장성과 유지보수성 향상
  • Spring과의 연관성 : Spring MVC의 DispatcherServlet 이 Front Controller Pattern이 적용된 Front Controller 역할을 한다.
  • FrontController Ver 1
    • 기본 Front Controller -> 모든 클라이언트의 요청을 하나의 진입점으로 모았다.
    • 모든 로직이 doDispatch에 집중된다.
    • 문제점 : 코드 비대화, 확장성 부족 (만약 새로운 업무 추가 시 공통 코드를 계속 변경해야 한다.)
doDispatch(request, response){
	if(requestType.equals("find"){
	// 직접 요청 처리 (비즈니스 처리)
	}else if(requestType.equals("register"){
	// 직접 요청 처리 (비즈니스 처리)
	}
}
  • FrontController Ver 2 
    • 메소드 분리, 단일 책임 원칙 적용
    • 가독성이 향상되었지만 여전히 한 클래스에 모든 로직이 존재하여 업무 추가 시 클래스가 비대해지고 관리가 어려움
doDispatch(request, response){
	if(){
	findCustomerById(request, response);
	}else if(){
	registerCustomer(request, response);
	}
}

findCustomerById(request, response){ }
registerCustomer(request, response){ }
  • FrontController Ver 3
    • 각 요청 처리 기능별 클래스를 분리
doDispatch(request, response){
	if(){
		FindCustomerController controller = new FindCustomerController();
	}else if(){
		RegisterCustomerController controller= new RegisterCustomerController();
	}
}

5. Command Design Pattern

  • 요청 처리를 전담하는 객체를 캡슐화하는 패턴으로, 각 기능 별로 독립적인 처리 객체를 만들어 관리한다.
  • 다양한 요청을 처리할 개별 컨트롤러들이 implements할 표준화를 위한 인터페이스로, 이렇게 계층 구조를 형성해 표준화하면 사용하는 FrontControllerServlet에서는 단일한 소통 방식으로 수많은 개별 컨트롤러를 제어(실행)할 수 있다.
  • Spring에서 동일한 이름으로 동일한 역할을 한다.
  • 실생활의 예 : 식당 주문 시스템
    • 고객 주문(request) : 주문서를 처리하는 객체(Command 객체 - Controller)
    • 주문서별로 전담 요리사 배정
    • 짬뽕 주문 -> 중화 요리사
    • 파스타 주문 -> 이탈리아 요리사
  • Command Pattern을 적용하지 않으면?
    • Front Controller 가 모든 기능을 구현해야 한다.
    • 코드 비대화, 단일 책임 원칙 위반, 새 기능 추가 시 공동 클래스를 수정, 테스트 어려움, 가독성 저하
  • Command Pattern 을 도입하면
    • 각 기능별 (요청 처리)로 독립적인 Command(Controller) 객체를 생성
    • 캡슐화 : 소통부와 구현부를 분리, FrontController는 소통부와 연동, 내부 구현부는 독립적으로 존재
    • 계층 구조를 형성 (interface 와 abstract)
    • 장점
      • 단일 책임 원칙 준수 : 각 Command(Controller)는 하나의 기능만 담당
      • 확장성 향상 : 비즈니스가 추가되면 해당 
      • 테스트 용이성 : 각 Command(Controller) 별로 독립 테스트 코드 재사용성 증대, 유지보수성 향상
  • Spring 과의 연관성 : Spring의 @Controller : Command(or Controller) @RequestMapping 메소드가 하나의 Command(Controller) 역할

6. Factory Design Pattern

  • 객체 생성 로직을 별도의 클래스로 분리하여 전담하게 하는 패턴
  • 사용하는 측에서 구체적인 클래스를 파악하지 않아도 생성할 수 있도록 한다.
  • 구체적 객체 생성부를 캡슐화한다.
  • HandlerMapping : 요청(request or command) 처리를 위한 각 컨트롤러 객체 생성을 전담하는 Factory class
  • 일반적으로 Factory는 시스템 상에서 단 하나만 존재하여 운영되므로 Singleton Pattern을 적용한다.
  • 결합도를 느슨하게 한다. (Loose Coupling)
  • 실생활의 예 : 자동차 공장
    • 고객 : SUV 주문
    • 공장 : 내부적으로 적절한 SUV 생성
    • 고객 : 제작 과정을 몰라도 SUV를 받아서 사용
  • 만약 Factory Pattern이 지원되지 않으면?
    • 사용하는 측에서 일일이 객체를 파악해서 생성해야 한다.
    • 요청 별로 요청 처리 객체를 일일이 생성해주어야 한다.
    • 문제점
      • 사용하는 측과 구체적 객체와는 강한 결합도를 가지므로 새롭게 요청 처리 클래스가 생기면 여러 곳에서 수정해야 한다. 따라서 확장성이 낮아진다.
      • 코드 중복이 발생하여 생산성이 저하된다.
  • Factory Pattern을 도입하면   
    • 사용하는 측에서는 command(요청 종류)만 전달하면 Factory가 알아서 해당 구체적인 객체를 생성해서 반환해준다.
    • 장점
      • 객체 생성 로직 중앙화(단일 책임 원칙)
      • 사용하는 측(FrontControllerServlet)과 실제 요청을 처리할 구현 객체와의 결합도가 느슨해진다.
      • 확장성 향상 : 만약 요구사항이 추가되어 고객 정보 수정 컨트롤러가 새롭게 구현되어야 할 경우 Factory Pattern적용 이전에는 FrontControllerServlet의 doDispatch 메소드 내부의 객체 생성부 코드가 업데이트 되어야 하는 구조 -> 결합도가 높아 유지보수성이 낮은 구조
        • Factory Pattern을 적용하면 사용하는 측(FrontControllerServlet)의 코드는 수정할 필요가 없어 결합도가 느슨해져 유지보수성, 확장성이 향상된다.
  •  Spring 과의 연관성 
    • Spring IOC Container : Factory Pattern 적용
    • Spring MVC의 HandlerMapping : Factory Pattern 적용

6-1. 웹 어플리케이션에서의 Factory Design Pattern

  • 컨트롤러 영역의 주요 컴포넌트
    • FrontControllerServlet : FrontController Design Pattern -> 모든 클라이언트 요청을 하나의 진입점으로 모아 공통 정책을 일관성있게 처리하는 디자인 패턴
    • Controller : 인터페이스, Command Design Pattern -> 요청 처리 객체를 캡슐화하여 다형성을 지원하는 디자인 패턴
    • HandlerMapping : Factory Pattern 객체 생성을 전담하는 디자인 패턴, 사용하는 측과 공급하는 측의 결합도를 느슨하게 한다.
  • Ver 5 : Factory Design Pattern 적용
    • 사용하는 측(FrontControllerServlet)과 서비스를 공급하는 측(개별 Controller들)과의 결합도를 낮추어서 유지보수성, 확장성을 향상
    • 객체 생성 전담 Factory인 HandlerMapping 으로 단일 책임 원칙 강화
public Controller create(String command) {
	Controller controller = null;
	if (command.equals("findbyid")) {
		controller = new FindCustomerByIdController();
	} else if
	...

7. Dynamic Factory Pattern

  • 클라이언트의 요청(command)에 대한 처리 로직을 정의한 객체들을 HandlerMapping Factory에서 전담해 객체를 생성하는 부분에서 요청의 종류가 증가(업무 추가)되므로 개별 요청 처리 컨트롤러 객체가 신규로 계속 추가되면 ver 5의 정적 팩토리 스타일은 매번 컨트롤러가 추가될 때마다 코드를 수정해야 한다.
    • 이를 자동화 할 수 있는 방안으로 Reflection API를 이용해 팩토리(HandlerMapping)를 Dynamic하게 동작시키도록 버전업을 한다.

7-1. Reflection API

  • 런타임(프로그램 실행 중) 시에 동적으로 객체를 생성하고 제어하기 위한 기술이다.
  • Ver 6 : 클라이언트에서 command = FindCustomerById 로 FrontController로 전달 <-> HandlerMapping(Factory)가 컨트롤러 객체 생성 전담
    • Dynamic Factory를 위한 작업 : HandlerMapping의 create(command) 구현부만 업데이트

8. Object Pool Design Pattern 

  • 객체 풀 패턴 : 객체 생성 및 소멸에 드는 자원 소모를 줄여 성능을 향상시키고 자원 낭비를 막는 목적의 디자인 패턴
  • 객체 생성에 드는 비용이 많이 드는 객체(ex : 데이터베이스 연동 시 Connection 객체)들을 미리 생성해서 Pool(풀)에 저장해두고 사용 후 다시 풀에 반납하여 재사용하는 방식

  • DBCP : Database Connection Pool 로 Object Pool Design Pattern 적용의 대표적인 예
    • db 컨넥션들을 pool에 미리 생성하고 사용 시 빌려주고 사용을 마치면 반납받는 방식으로 시스템 성능을 향상시키는 기술
  • DataSource Interface : javax.sql.DataSource
    • 다양한 DBCP 객체들(BasicDataSource, Hikari CP)을 표준화된 방식으로 관리하기 위한 인터페이스
    • BasicDataSource : apache tomcat 에서 제공하는 dbcp 구현체로, javax.sql.DataSource interface의 하위 클래스(구현체)

9. 정리

개발 순서 : Controller(Command 패턴)→ HandleMapping(Factory 패턴) → FrontController → Find, Register, Update 등의 controller

 

'교육' 카테고리의 다른 글

13주차 - Thymeleaf  (0) 2025.07.28
12주차 - Spring  (0) 2025.07.20
10주차 - Servlet  (0) 2025.07.06
9주차 - Web  (0) 2025.06.29
6, 7, 8주차 - DB와 JDBC  (0) 2025.06.14