Delegate
로 게시판을 만든다?
 
처음 우리가 웹을 접하면서 많은 부분을 할애하며 배우는 것이 게시판이다. “뭐 게시판 쯤이야” 라고 할지라도, 처음 계층형 게시판 만들기를 연습하면서 가장 머리가 뽀개질 것 같던 시간이었다. ^^;
 
게시판 만들기를 수없이 연습해 보았다면, 이젠 게시판을 어떤 구조로 만들 것인가가 중요할 것이다. 하지만, 여기에선 게시판을 통채로 만들진 않을 것이다.
이런 방법도 있다는 것도 알아두면 좋을 듯 하다.
 
위 구조는 대략 다음과 같은 다이어그램을 나타낸다.
 
 
 
소스를 보면 알겠지만, 데이터를 읽은 모든 과정은 델리게이트에게 위임하였다.
 
위와 같이 구성함으로써, DataAccess 부분으로 집중하게 될 데이터를 가져오게 될 부분을 각각 페이지로 분산시켰고, 이로써 해당 페이지에서 필요한 데이터만을 가져옴으로써, List, View, Write 페이지 및 다른 기타 페이지에서 융통성 있게 코드를 작성할 수 있다.
그러므로, DataAccess 의 코드는 그만큼 간결해 질 수 있다.
 
 
소스 살펴보기
 
///<summary>
///리스트에 출력될 데이터 모델
///</summary>
public class ListModel
{
         public ListModel()
         {
         }
 
         private string title;
         private string content;
 
         ///<summary>
         ///타이틀
         ///</summary>
         public string Title
         {
                  get { return title; }
                  set { title = value; }
         }
 
         ///<summary>
         ///내용
         ///</summary>
         public string Content
         {
                  get { return content; }
                  set { content = value; }
         }
}
[클래스 1] ListModel.cs
 
위 소스는 일반적으로 List 페이지에 뿌려질 부분의 공통적인 부분을 추출한 Entity Class 이다. 필요한 만큼 추가하면 된다.
 
 
///<summary>
/// DataAccess 클래스
///</summary>
public abstract class DataAccess
{
         public static readonly string ConnectionString = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
 
         public delegate void FormatListRow( IDataRecord row, List<ListModel> model );
 
         public static List<ListModel> GetData( string table, FormatListRow listRow )
         {
                  SqlCommand cmd                     = null;
                  SqlDataReader reader       = null;
 
                  try
                  {
                           cmd               = new SqlCommand(
                                                              string.Format("SELECT * FROM {0}", table),
                                                              new SqlConnection(ConnectionString));
                           cmd.Connection.Open();
                           reader   = cmd.ExecuteReader(CommandBehavior.CloseConnection);
 
                           List<ListModel> model = new List<ListModel>();
 
                           while (reader.Read())
                           {
                                   listRow(reader, model);
                           }
 
                           return model;
                  }
                  catch (Exception ex)
                  {
                           throw ex;
                  }
                  finally
                  {
                           reader.Close();
                  }
         }
}
[클래스 2] DataAccess.cs
 
위 코드에서
 
public delegate void FormatListRow( IDataRecord row, List<ListModel> model );
 
이 델리게이트가 바로 데이터를 읽는 부분을 처리해줄 대리자이다.
IDataRow row 는 DataReader 의 각 ROW 를 가져오기 위한 인자이고, List<ListModel> 은 리스트목록을 저장하게 될 제네릭 컬렉션이다.
 
public static List<ListModel> GetData( string table, FormatListRow listRow )
{
while (reader.Read())
{
                  listRow(reader, model);
}
}
 
GetData 메서드는 테이블명을 인자로 받아 단순한 SELECT 쿼리를 수행한다.
 
이 코드에서 보듯이 인자값으로 델리게이트도 받을 수 있다. 이 델리게이트엔 어떤 메서드가 위임 되어 있을 것이다.
Delegate 에 메서드를 위임 하였다면 우리는 delegate 의 참조만으로 언제 어디서든 위임된 메서드를 실행 할 수 있게 되는 것이다.
 
 
///<summary>
/// ListUserControl 의 필수 구현 메서드/프로퍼티
///</summary>
public abstract class ListUserControl : UserControl
{
         public abstract void RowFormatter(IDataRecord row, List<ListModel> model);
 
         public virtual DataAccess.FormatListRow ListFormatter
         {
                  get { return new DataAccess.FormatListRow(RowFormatter); }
         }                              
}
[클래스 3] ListUserControl.cs
 
위 클래스는 샘플의 작성을 위해 임의로 구성해 본 것이다. 반듯이 위 코드처럼 구현할 필요는 없다.
우리는 Abstract 로 선언된 RowFormatter 메서드만 구현해 주면 된다.
RowFormatter 는 델리게이트에 위임할 메서드이므로 델리게이트로 선언한 인지와 반환값은 반듯이 일치해야 한다.
 
ListFormatter 프로퍼티는 델리게이트에 메서드를 위임하는 프로퍼티이다.
 
return new DataAccess.FormatListRow(RowFormatter);
 
과 같이 단순히 델리게이트에 메서드를 위임하는 하나의 과정일 뿐이다.
 
 
페이지 구성하기
 
Default.aspx 페이지는 두개의 LinkButton 에 따라 서로다른 UserControl 을 보여준다.
이 부분은 간단하므로 생략하도록 한다.
 
그럼 두개의 UserControl 소스를 연속으로 보도록 하자.
 
public partial class Stores : ListUserControl
{
         protected void Page_Load(object sender, EventArgs e)
         {
                  dgList.DataSource = DataAccess.GetData( "Stores", ListFormatter );
                  dgList.DataBind();
         }
 
         public override void RowFormatter(IDataRecord row, List<ListModel> model)
         {
                  ListModel rowModel         = new ListModel();
                  rowModel.Title             = row["Stor_Name"].ToString();
                  rowModel.Content = row["Stor_Address"].ToString();
 
                  model.Add( rowModel );
         }
}
 
[클래스 4] Stores.ascx.cs
 
public partial class Titles : ListUserControl
{
         protected void Page_Load(object sender, EventArgs e)
         {
                  dgList.DataSource = DataAccess.GetData( "Titles", ListFormatter );
                  dgList.DataBind();
         }
 
         public override void RowFormatter( IDataRecord row, List<ListModel> model )
         {
                  ListModel rowModel         = new ListModel();
                  rowModel.Title             = row["Title"].ToString();
                  rowModel.Content = row["Notes"].ToString();
 
                  model.Add( rowModel );
         }
}
[클래스 5] Titles.ascx.cs
 
위 코드는 얼핏 비슷해 보인다.
아마 이쯤에서 “아하” 하는 분들도 계실 것이다.
 
dgList.DataSource = DataAccess.GetData( "Titles", ListFormatter );
 
ListFormatter 프로퍼티는 생성된 객체의 RowFormatter 를 리턴하는 프로퍼티인 것을 기억할 것이다.
RowFormatter 는 각각의 페이지에서 필요한 데이터베이스 컬럼만을 추출하는 메서드이다.
페이지 내에서 필요한 데이터는 페이지에서 코드를 작성하면 된다.
 
각 페이지에서 필요한 데이터는 DataAccess 를 거치지 않고, 페이지 안에 정의함으로써 대리자에게 메서드의 실행을 위임하였다.
DataAccess 내에서 필요한 메서드를 각각의 페이지로 분산 시켰고, 결국 DataAccess 클래스는 한층 간결해 졌다. 페이지 코드 또한, 이리저리 클래스를 살펴볼 필요없이, 자기 페이지안에 작성함으로써 얻는 잇점이 더 클 것이다.
 
 
마치며…
 
실제로 실무 2개의 프로젝트에서 위와 같은 방법으로
[.NET/ASP.NET] - Composite Pattern 을 사용하여 MVC Pattern 구현
에서 기술한 패턴을 토대로 구현해 본 결과, 굉장히 효과적으로 코드를 작성 할 수 있었고, 관리 또한 굉장히 수월했었다.
그냥 이런 방법으로 구성 할 수 도 있다는 것 정도만 알아둬도 좋을 것 같다.
 
그럼 이만, 오늘도, 내일도, 다함께.. 고고씽~~
저작자 표시 비영리 동일 조건 변경 허락
신고
Posted by 땡초 POWERUMC

댓글을 달아 주세요

  1. 지송 2009.07.01 11:38 신고 Address Modify/Delete Reply

    이런 방법도 있군요.. 잘보고 갑니다. ^^