4.     The View Helper Pattern

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

 

구조


사용자 삽입 이미지

View Helper pattern class diagram

일반적으로view화면이JSP일경우HelperJSP 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패턴의 가장 단순한 모습을 보여준다.가장 낮은 수준의 개발법이라 할수 있을 것이다.

 

역할

n         View :

뷰는 클라이언트에게 정보를 보여준다.디스플레이에 사용되는 정보는 모델로부터 검색된다. Helper는 디스플레이에서 사용할 모델을 캡슐화하고 적용함으로써 뷰를 지원한다.

 

n         Helper :

Helper는 뷰와 컨트롤러를 지원하는 역할을 한다.따라서, helper는 뷰에서 요청하는 데이터를 수집하고,뷰에서 사용할 데이터 모델을 적용하는 것을 포함하여(GoFAdaptor패턴을 참조하라)다양한 역할을 하게된다. Helper는 뷰의 데이터 요청에 대하여,가공되지 않은 데이터에 직접 접속하도록 하거나,웹 컨텐트로 만들어진 데이터를 제공한다.

뷰는 여러Helper들과 함께 동작할 것이며, Helper들은 대체로JavaBeans (JSP 1.0)이나Custom Tags (JSP 1.1+)로 구현되어진다.추가적으로, HelperCommand객체나Delegate객체(Business Delegate패턴 참조),또는XSL변형처리 객체를 나타내어,모델을 적합한 형태로 변형하기위한 스타일쉬트와 함께 사용된다.

 

n         ValueBean :

Helper에서BusinessService에게 요청한 데이터의Transfer Object(전송객체)View에게 전달 되는 객체이다.

 

n         BusinessService :

BusinessService의 역할은 클라이언트에게서 요청된Business메서드를 포함하고 있다.

BusinessServlce는 직접적인Model이거나Business delegate일수 있다.

 

의도

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

 

결론

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

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

n       재사용성
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 Tagcollection형태의 결과에 전반적으로 반복될수 있고,이 결과를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>


사용자 삽입 이미지

 

 

'Programming > Design Pattern' 카테고리의 다른 글

[펌] The Interception Filter Pattern  (0) 2006.01.21
[펌] The Front Controller Pattern  (0) 2006.01.21
[펌] The Composite View pattern  (0) 2006.01.21
[펌] The Observer Pattern  (0) 2006.01.21
[펌] The Observer Pattern  (0) 2006.01.21

Posted by 영웅기삼
,