2011년 5월 23일 월요일

The View Helper Pattern

4. The View Helper Pattern
프리젠테이션 티어의 변동은 수시로 일어나며, 비즈니스 데이터 액세스 로직과 화면에 나타내는 로직을 결합하는 데 있어, 개발하고 유지보수하는 것이 어렵다. 이로 인해 시스템은 유연하지 못하고, 재사용이 어려워지며, 변동사항에 처리가 불편하다. 비즈니스와 시스템 로직을 뷰 처리에 혼합하는 것은 모듈화를 저하시키고, 웹 제작팀과 소프트웨어 개발자 간의 역할 분리도 곤란하다.
구조

View Helper pattern class diagram


일반적으로 view화면이 JSP일경우 Helper는 JSP Beans이거나 custom tags이다.

View Helper sequence diagram


MVC모델 2을 기반으로 웹 어플리케이션을 작성한다고 할 때 view Helper만을 이용한 Business service 접근은 최소한 피하여야 한다. Controller을 통한 Business service을 접근한다는 것은 창구 단일화로 일하여 응집력을 강화하고 각 역할별로 Command, Helper을 둡으로써 결합도를 낮추는 역할을 하지만 창구 단일화가 되지 않는다는 것은 MVC모델 2사용의 이점을 잃어버는 것이된다.

View Helper simple sequence diagram


View Helper 패턴의 가장 단순한 모습을 보여준다. 가장 낮은 수준의 개발법이라 할수 있을 것이다.

역할
View :
뷰는 클라이언트에게 정보를 보여준다. 디스플레이에 사용되는 정보는 모델로부터 검색된다. Helper는 디스플레이에서 사용할 모델을 캡슐화하고 적용함으로써 뷰를 지원한다.
Helper :
Helper는 뷰와 컨트롤러를 지원하는 역할을 한다. 따라서, helper는 뷰에서 요청하는 데이터를 수집하고, 뷰에서 사용할 데이터 모델을 적용하는 것을 포함하여(GoF의 Adaptor 패턴을 참조하라) 다양한 역할을 하게된다. Helper는 뷰의 데이터 요청에 대하여, 가공되지 않은 데이터에 직접 접속하도록 하거나, 웹 컨텐트로 만들어진 데이터를 제공한다.
뷰는 여러 Helper들과 함께 동작할 것이며, Helper들은 대체로 JavaBeans (JSP 1.0)이나 Custom Tags (JSP 1.1+)로 구현되어진다. 추가적으로, Helper는 Command 객체나 Delegate 객체(Business Delegate 패턴 참조), 또는 XSL 변형처리 객체를 나타내어, 모델을 적합한 형태로 변형하기위한 스타일쉬트와 함께 사용된다.
ValueBean :
Helper에서 BusinessService에게 요청한 데이터의 Transfer Object(전송객체)로 View에게 전달 되는 객체이다.
BusinessService :
BusinessService의 역할은 클라이언트에게서 요청된 Business 메서드를 포함하고 있다.
BusinessServlce는 직접적인 Model이거나 Business delegate일수 있다.

의도
다른 로직(비즈니스 로직)에서 프레젠테이션(출력의 포매팅)에 대한 책임을 가지고 있는 프로그래밍 로직의 분리를 위한 솔루션을 제공한다. 프레젠테이션 포매팅은 View 컴포넌트에 위치하며, 이것은 복잡한 뷰의 구성을 위해 다중 서브컴포넌트로 구성하는 것이 가능하다. 비즈니스 로직의 코드는 Helper컴포넌트에 위치한다. Helper 컴포넌트의 전형적인 기능들로는 컨텐츠 검색, 검증, 적용이 있다. Helper 컴포넌트는 Business Service 접근하기 위해 Business Delegate 패턴을 사용할 수 있다.

결론

향상된 어플리케이션 분리
Helper를 사용하는 것은 어플리케이션에서 비즈니스 처리로부터 뷰를 명확하게 분리하도록 한다. JavaBeans(JSP 1.0)이나 Custom Tag(JSP1.1 이상) 형태의 Helper는 JSP로부터 비즈니스 로직을 추출해낼 장소를 제공한다. JSP 내에서, 스크립틀렛 코드는 곧 길어지게 되고, 큰 프로젝트에서는 처리하기가 불편한다.

향상된 역할 분리
어플리케이션의 비즈니스 로직으로부터 가공된 로직을 분리하는 것은 또한 각자 다른 역할을 하는 개인들이 동일한 자원에 대해 가질 수 있는 의존성을 줄인다. 예를 들어, 소프트웨어 개발자는 HTML 마크업 안에 싸여진 코드를 담당할 것이고, 반면에 웹 제작팀 멤버는 페이지 레이아웃이나, 비즈니스 로직과 섞여있는 디자인 컴포넌트를 수정하여야 할 것이다. 이러한 역할을 수행하는 개인들은 다른 사람들의 구현내용에 익숙하지 않을 뿐더러, 이런 상태에서의 수정작업은 시스템에 버그를 만들 수 있는 위험성을 높인다.

재사용성
JSP에서 추출되어 JavaBean이나 Custom Tag에 넣어진 비즈니스 로직은 수많은 JSP들에 걸쳐 재사용될 것이다. 많은 다른 JSP에서 코드가 중복되지 않고, 따라서 유지보수나 디버깅이 용이하다. 또한, 로직이 뷰로부터 제거되었으므로, Swing UI와 같이, 전적으로 다른 사용자 인터페이스를 서비스하는 데 있어, 동일한 비즈니스 로직을 수정작업 없이 재사용할 것이다.
JavaBean Helper는 컨텐트 검색이나, 뷰를 위한 모델을 만들고 저장하는 것을 보조하기위해 사용하는 것이 가장 적합하다. JavaBean Helper는 또한 command 객체로 쓰이기도 한다.
JavaBean Helper와 마찬가지로 Custom Tag Helper도 이러한 역할을 수행하지만, command 객체로는 사용되지 않는다. JavaBean Helper와 달리, CustomTagHelper는 뷰 내부에서의 흐름과 반복을 제어하기 위해 사용하기에 좋다. 이렇게 사용되는 Custom Tag Helper는, Custom Tag Helper를 사용하지 않을 경우에는 JSP에 스크립틀렛 코드로 직접 포함되었을 로직을 캡슐화한다. Custom Tag Helper의 사용이 선호되는 또다른 경우는, 화면 데이터를 디스플레이하기 좋게 만들기 위함이다. Custom Tag는 collection 형태의 결과에 전반적으로 반복될수 있고, 이 결과를 HTML 테이블 형태로 만들 수 있으며, 자바 스크립틀렛 코딩없이, JSP 뷰안에 테이블을 포함시킬수 있다.


예제소스
Class Diagram


소스
package viewHelper;
public class valueBean {
private String name;
private String email;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
package viewHelper;
import java.util.ArrayList;
public class businessService {
private static ArrayList array = new ArrayList();
public businessService() {
}
public static valueBean[] getMailList() {
valueBean[] values = new valueBean[array.size()];
array.toArray(values);
return values;
}
public static void addMail(valueBean value) {
array.add(value);
}
public static void delMail(valueBean value) {
for(int i=0; i<array.size(); i++) {
if(((valueBean)array.get(i)).getName().equals(value.getName()))
array.remove(i);
}
}
}
package viewHelper;
public class helper {
private String mode;
public helper() {
}
public valueBean[] getMailList() {
return businessService.getMailList();
}
public void addMail(valueBean value) {
businessService.addMail(value);
}
public void delMail(valueBean value) {
businessService.delMail(value);
}
public String getMode() {
if(mode == null)
return "";
else
return mode;
}
public void setMode(String mode) {
this.mode = mode;
}
public void command(valueBean value) {
if(getMode().equals("add"))
addMail(value);
else if(getMode().equals("del"))
delMail(value);
}
}
<%@ page contentType="text/html;charset=EUC-KR"%>
<%@ page import="viewHelper.valueBean"%>
<%@ page import="viewHelper.helper"%>
<jsp:useBean id="vo" class="viewHelper.valueBean" scope="request"/>
<jsp:setProperty name="vo" property="*"/>
<jsp:useBean id="helper" class="viewHelper.helper" scope="request"/>
<jsp:setProperty name="helper" property="*"/>
<%
helper.command(vo);
valueBean[] values = helper.getMailList();
%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=EUC-KR">
<title>vieHelper</title>
<SCRIPT>
function reCall(mode) {
var ff = document.form;
ff.mode.value = mode;
ff.action = 'view.jsp';
ff.method = 'post';
ff.submit();
}
</SCRIPT>
</head>
<body>
<P>
<STRONG><FONT size="6">View Helper Pattern</FONT></STRONG>
</P>
<hr/>
<P>
Total Num(<%=values.length%>)
<BR/>
<STRONG>Mail List</STRONG>
</P>
<table cellspacing="2" cellpadding="3" border="1" width="100%">
<tr>
<td bgcolor="#cccccc">
<DIV align="center">Name</DIV>
</td>
<td bgcolor="#cccccc">
<DIV align="center">EMail</DIV>
</td>
<td bgcolor="#cccccc">
<DIV align="center">Age</DIV>
</td>
</tr>
<% for( int i = 0; i < values.length; i++ ) {%>
<tr>
<td>
<DIV align="left"><%=values[i].getName()%></DIV>
</td>
<td>
<DIV align="left"><%=values[i].getEmail()%></DIV>
</td>
<td>
<DIV align="left"><%=values[i].getAge()%></DIV>
</td>
</tr>
<% } %>
</table>
<P>&nbsp;</P>
<P>
<STRONG>Insert &amp; Delete</STRONG>
</P>
<form name="form">
<table cellspacing="3" cellpadding="2" border="1" width="100%">
<input type="HIDDEN" name="mode">
<tr>
<td width="15%">Name</td>
<td width="85%">
<input type="text" name="name"/>
</td>
</tr>
<tr>
<td width="15%">EMail</td>
<td width="85%">
<input type="text" name="email"/>
</td>
</tr>
<tr>
<td width="15%">Age</td>
<td width="85%">
<input type="text" name="age"/>
</td>
</tr>
<tr>
<td width="15%">&nbsp;</td>
<td width="85%">
<input type="BUTTON" name="addMail" value="Add Mail" omclick="reCall('add');">
<input type="BUTTON" name="delMail" value="Del Mail" omclick="reCall('del');">
</td>
</tr>
</table>
</form>
<P>&nbsp;</P>
</body>
</html>

댓글 없음:

댓글 쓰기

ETL 솔루션 환경

ETL 솔루션 환경 하둡은 대용량 데이터를 값싸고 빠르게 분석할 수 있는 길을 만들어줬다. 통계분석 엔진인 “R”역시 하둡 못지 않게 관심을 받고 있다. 빅데이터 역시 데이터라는 점을 볼때 분산처리와 분석 그 이전에 데이터 품질 등 데이...