1. 디자인 패턴 꼭 써야 한다

de_sj_awa·2021년 8월 28일
0
post-custom-banner

1. 디자인 패턴 꼭 써야 한다

1. Spring MVC

MVC

  • Model, View, Controller의 약자, 모델 역할, 뷰 역할, 컨트롤러 역할을 하는 클래스를 각각 만들어서 개발하는 모델이다.
  • 뷰 : 사용자가 결과를 보거나 입력할 수 있는 화면, 이벤트를 발생시키고, 이벤트의 결과를 보여주는 역할을 한다.
  • 컨트롤러 : 뷰와 모델의 연결자. 뷰에서 받은 이벤트를 모델로 연결하는 역할을 한다.
  • 모델 : 뷰에서 입력된 내용을 저장, 관리, 수정하는 역할을 한다. 이벤트에 대한 실절적인 일을 하는 부분이다.

JSP 모델1

  • JSP 모델1은 JSP에서 자바 빈을 호출하고 데이터베이스에서 정보를 조회, 등록, 수정, 삭제 업무를 한 후 결과를 브라우저로 보내주는 방식이다.
  • 간단하게 개발할 수 있다는 장점이 있지만, 개발 후 프로세스 변경이 생길 경우에 수정이 어렵다는 단점이 있다.
  • 더 큰 문제는, 이러한 구조로 개발하면 화면과 비즈니스 모델의 분업화가 어려둬 개발자의 역량에 따라서 코드가 많이 달라질 수 잇다는 것이다. 또한 이 모델은 컨트롤러가 없기 때문에 MVC 모델이라고 하기는 어렵다.

JSP 모델2

  • JSP 모델1의 단점을 해결하기 위해 나온 모델. JSP 모델2는 MVC 모델을 정확히 따른다.
  • JSP로 요청을 직접 하는 JSP 모델1과 가장 큰 차이점은 서블릿으로 요청을 한다는 것이다. 모델2에서는 서블릿이 컨트롤러 역할을 수행한다.

2. J2EE 디자인 패턴이란?

디자인 패턴

  • 시스템을 만들기 위해서 전체 중 의미 있는 클래스들을 묶은 각각의 집합을 디자인 패턴이라고 생각하면 된다. 반복되는 의미 있는 집합을 정의하고 이름을 지정해서, 누가 이야기하더라도 동일한 의미의 패턴이 되도록 만들어 놓은 것이다.

이 그림은 사용자의 요청이 처리되는 순서로 생각하면서 위에서부터 아래로 보면 된다. 가장 윗 부분은 프리젠테이션 티어이고, 중간 부분은 비즈니스 티어, 하단 부분은 인테그레이션 티어이다. 위에 갈수록 화면에 가깝고, 아래로 갈수록 DB와 같은 저장소에 가깝다고 생각하면 된다. 각 패턴의 특징을 간단히 알아보면 다음과 같다.

  • Intercepting Filter 패턴 : 요청 타입 결과에 따라 다른 처리를 하기 위한 패턴이다.
  • Front Controller 패턴 : 요청 전후에 처리하기 위한 컨트롤러를 지정하는 패턴이다.
  • View Helper 패턴 : 프리젠테이션 로직과 상관 없는 비즈니스 로직을 헬퍼로 지정하는 패턴이다.
  • Composite View 패턴 : 최소 단위의 하위 컴포넌트를 분리하는 패턴이다.
  • Service to Worker 패턴 : Front Controller와 View Helper 사이에 디스패처를 두어 조합하는 패턴이다.
  • Dispatcher View 패턴 : Front Controller와 View Helper로 디스패처 컴포넌트를 형성한다. 뷰 처리가 종료될 때까지 다른 활동을 지연한다는 점이 Service to Worker 패턴과 다르다.
  • Business Delegate 패턴 : 비즈니스 서비스 접근을 캡슐화하는 패턴이다.
  • Service Locator 패턴 : 서비스와 컴포넌트 검색을 쉽게 하는 패턴이다.
  • Session Facade 패턴 : 비즈니스 티어 컴포넌트를 캡슐화하고, 원격 클라이언트에서 접근할 수 있는 서비스를 제공하는 패턴이다.
  • Composite Entity 패턴 : 로컬 엔티티 빈과 POJO를 이용하여 큰 단위의 엔티티 객체를 구현한다.
  • Transfer Object 패턴 : 일명 Value Object 패턴이라고 많이 알려져 있다. 데이터를 전송하기 위한 객체에 대한 패턴이다.
  • Transfer Object Assembler 패턴 : 하나의 Transfer Object로 모든 타입 데이터를 처리할 수 없으므로, 여러 Transfer Object를 조합하거나 변형한 객체를 생성하여 사용하는 패턴이다.
  • Value List Handler 패턴 : 데이터 조회를 처리하고, 결과를 임시 저장하며, 결과 집합을 선택하여 필요한 항목을 선택하는 역할을 수행한다.
  • Data Access Object 패턴 : 일명 DAO라고 많이 알려져 있다. DB에 접근을 전담하는 클래스를 추상화하고 캡슐화한다.
  • Service Activator 패턴 : 비동기적 호출을 처리하기 위한 패턴이다.

여기서 Service to Worker 패턴과 Dispatcher View 패턴이 의미가 비슷하여 혼동될 수 있는데, 클래스 다이어그램을 보면 다음과 같은 차이가 있다.
위의 다이어그램을 보면, Dispatcher View 패턴은 Helper 클래스를 직접 컨트롤하지 않는다는 차이가 있다.

위에 명시된 패턴 중 성능과 관련된 패턴은 무엇일까? 패턴은 모두 직간접적으로 성능과 관려이 있는데, J2EE 패턴 중 성능과 가장 밀접한 패턴은 Service Locator 패턴이다. 그리고 성능에 직접적으로 많은 영향을 미치지는 않지만, 애플리케이션 개발 시 반드시 사용해야 하는 Transfer Object 패턴도 짚고 넘어가야 한다.
적어도 위 패턴에서 Business Delegate, Session Facade, Data Access Obejct, Service Locator, Transfer Object 패턴에 대해서 알아야 한다. 이 중 성능과 관련이 있는 Tranfer Object, Service Locator 패턴에 대해서 알아보자.

3. Tranfer Object 패턴

Value Object라고 불리는 Transfer Object는 데이터를 전송하기 위한 객체에 대한 패턴이다. 먼저 Tranfer Object 예제 소스 코드를 보자.

package com.perf.pattern;

import java.io.Serializable;

public class EmployeeTO implements Serializable {
  private String empName;
  private String empID;
  private String empPhone;
  
  public EmployeeTO() {
    super();
  }
  
  public EmployeeTO(String empName, String empID, String empPhone) {
    this.empName = empName;
    this.empID = empID;
    this.empPhone = empPhone;
  }

  public String getEmpName() {
    if(empName==null) return "";
    else return empName;
  }

  public void setEmpName(String empName) {
    this.empName = empName;
  }

  public String getEmpID() {
    return empID;
  }

  public void setEmpID(String empID) {
    this.empID = empID;
  }

  public String getEmpPhone() {
    return empPhone;
  }

  public void setEmpPhone(String empPhone) {
    this.empPhone = empPhone;
  }

  @Override
  public String toString() {
    StringBuilder sb = new StringBuilder();
    sb.append("empName=").append(empName).append("empID=").append(empID)
        .append( " empPhone=").append(empPhone);
    return sb.toString();
  }
}
  • Transfer Object 패턴은 Transfer Object를 만들어 하나의 객체에 여러 타입의 값을 전달하는 일을 수행한다.
  • Tranfer Object를 사용할 때 필드를 private로 지정해서 getter() 메서드와 setter() 메서드를 만들어야 할지, 아니면 public으로 지정해서 메서드를 만들지 않을지에 대한 정답은 없지만, 성능상으로 따져볼 때 getter()와 setter()를 만들지 않는 것이 더 빠르다. 하지만 정보를 은닉하고, 모든 필드의 값들을 아무나 마음대로 수정할 수 없게 하려면 위의 코드와 같이 각 getter(), setter() 메서드를 작성하는 것이 일반적이다.
  • 게다가, 각 setter()와 getter()를 이클립스와 기타 개발 툴에서 자동으로 생성해주는 기능이 있기 때문에 그리 불편한 일을 아니다.
  • 그리고 getter() 메서드나 setter() 메서드를 사용하면 getEmpName() 메서드처럼 empName이 null 값이더라도 null을 리턴하지 않고 길이가 0인 String을 리턴한다. 즉, Transfer Object를 잘 만들어 놓으면 각 소스에서 일일이 null 체크를 할 필요가 없기 때문에 개발할 때 오히려 더 편해진다.
  • Transfer Object를 생성할 때는 반드시 toString() 메서드를 구현해야 한다. 이 메서드를 구현하지 않고 toString() 메서드를 수행하면 com.perf.pattern.EmployEETo@c1716처럼 알 수 없는 값을 리턴한다. 나중에 JUnit 기반에서 테스트해보면 값 비교를 할 때나 데이터를 확인할 일이 있을 때 매우 유용하게 사용하게 된다.
  • Serializable을 구현하면 객체를 직렬화할 수 있다. 다시 말해 서버 사이의 데이터 전송이 가능해진다. 그러므로 원격지 서버에 데이터를 전송하거나, 파일로 객체를 저장할 경우에는 이 인터페이스를 구현해야 한다.

그렇다면 이 Transfer Obejct를 사용한다고 성능이 좋아질까? 이 패턴을 사용한다고 애플리케이션에 엄청난 성능 개선 효과가 발생하는 것은 아니다. 하지만 하나의 객체에 결과 값을 담아올 수 있어 두 번, 세 번씩 요청을 하는 일이 발생하는 것을 줄여주므로, 이 패턴을 사용하기를 권장한다.

4. Service Locator 패턴

package com.perf.pattern;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import javax.naming.InitialContext;

public class ServiceLocator {

  private InitialContext ic;
  private Map cache;
  private static ServiceLocator me;

  static {
    me = new ServiceLocator();
  }

  private ServiceLocator() {
    cache = Collections.synchronizedMap(new HashMap());
  }

  public InitialContext getInitialContext() throws Exception {
    try {
      if (ic == null) {
        ic = new InitialContext();
      }
    } catch (Exception e) {
        throw e;
    }
    return ic;
  }

  public static ServiceLocator getInstance() {
    return me;
  }
  // ... 지면상 생략
}

Service Locator 패턴은 예전에 많이 사용되었던 EJB의 Home 객체와 DB의 DataSource를 찾을 때(lookup 할 때) 소요되는 응답 속도를 감소시키기 위해서 사용된다. 위의 소스를 간단히 보면, cache라는 Map 객체에 home 객체를 찾은 결과를 보관하고 있다가, 누군가 그 객체를 필요로 할 때 메모리에서 찾아서 제공하도록 되어 있다. 만약 해당 객체가 cache라는 맵에 없으면 메모리에서 찾는다.

참고

  • 자바 성능 튜닝 이야기
profile
이것저것 관심많은 개발자.
post-custom-banner

0개의 댓글