Business into software

openyou.egloos.com

방명록?



2.1.5. Builder 객체지향 디자인패턴



다이어그램1.

다이어그램2.


다이어그램 3(Sequential)

Separate the construction of a complex object from its representation so that the same construction process can create different representations

복합객체의 생성을 표현?으로부터 분리함으로서 동일한 생성프로세스가 서로다른 표현들로 나타난다.
필자가 이해한 바로는 부분으로 구성된 완전한 제품하나를
 동적으로생산한 후 부분의 조합으로 나타나는 완성된 기능을 이용하는 패턴이다.
물론 정의도 맞다. direct에서 construct호출 시 여러 개의 ConcreteBuilder를 생성하면 당연히 서로다른 표현들로 나타난다.(이는 유사 다른패턴들에도 얼마든지 존재하는 특징이라서 필자의 맘에 들지않는 정의이다)

위의 정의는 Director의 기능을 보면
복합객체(=구현팩토리클래스로 표현되는 객체, 추상팩토리패턴참고)를 생성함에있어 생성을 본래의 표현으로부터 분리함으로써 동일한 생성과정을 다른 표현들로 생성 할 수 있다. |라는 의미로 해석이 되는데 아래 다이어 그램을 기준으로 생각 해 보면 ConcreteBuilder의 생성자에서 모든 생성을 제공 해도 되지만 아마도 유연성적인 측면에서 Director클래스에서 생성을 전담하게 함으로써 클라이언트가 개별생성에 신경 안쓰고 Director에게 의뢰만 함으로써 구현복합객체를 사용할 수 있게 한다는 것이다.
이렇게 생성을 분리해 두면 생성과정(공정)의 변화등에 아주 유연하게 대처 할 수 있는 이점이 있을 것이다.
(Director가 없으면 빌더패턴이 아니냐? 없어도 빌더패턴입니다. 클라이언트가 직접 builder객체를 만들어서 사용하면 돼죠, 유연성을 제공차원의 Director입니다.)

부분 구현객체(Product)를 생성하는 BuildPart1~N개를 수행 후 내부적으로 조합된 결과가 구현팩토리클래스(ConcreteBuilder)객체의 GetResult()메소드를 통해 리턴된다.(추상팩토리패턴 참고)
Builde를 자동차로 보면 ConcreteBuilder1는 특정회사의 자동차(예,현대자동차)에 해당 되며 부분 부속품들을 빌더(조합)한 결과이다



닷넷에서 만약에 DbProviderFactory가 제공하는 SqlDbProvider,OracleDbProvider,OleDbProvider를 Builder패턴으로 만들어 사용하는 경우를 생각해 보면 다음과 같은 가상코드가 나오게 된다.
1. Builder 추상클래스
 abstract class Builder
 {
    public abstract void BuildConnection();
    public abstract void BuildCommand();

    public abstract void BuildParameter();
    public abstract DbProvider GetResult(); // DbProvider는 추상클래스가 아닌 일반 클래스라고 가정한다.
}

2. Builder 구현 클래스
  class SqlDbProviderBuilder : Builder
  {
    private DbProvider dbProvider = new DbProvider();
    public override void BuildConnection()
    {

        SqlDbConnection Connection = new SqlDbConnection()
        product.Add(Connection );
    }
    public override void BuildCommand()
    {

        SqlDbCommand Command = new SqlDbCommand ()
        product.Add(Command);
    }
    public override DbProvider GetResult()
    {
        return dbProvider ;
    }
  }

  // OracleDbProvider도 거의 똑같은 구현이 될것이므로 생략

3. DbProvider

  class DbProvider
  {
    ArrayList parts = new ArrayList();

    public void Add(object objPart)  // 즉 추상객체를 동적으로 추가하게 된다.
    {
      parts.Add(objPart);
    }

    public DataSet SelectDataSet()
    {
      Console.WriteLine("\nDvProvider objects -------");
      //foreach (object part in parts)
      //  Console.WriteLine(part);

      //Connection,Command,Parameter가 arrayList에 존재하므로 꺼내서 exectute시킨후 결과를 리턴 
    }
  }

    
 

3. "Director" 

  class Director
  {
    // Builder uses a complex series of steps
    public void Construct(ArrayList arrBuilder)
    {
        forech ( Builder builder in arrBuilder )
        {
            builder.BuildConnection();
            builder.BuildCommand();

            builder.BuildParameter();

            DbProvider dbProvider = buile.GetResult();
            DataSet ds =  dbProvider.SelectDataSet();

             //각 DB별로 Select한 내용을 일괄처리...한다??

        }
    }
  }

    public static void Main()
    {
      // Create director and builders
      ArrayList<Builder> builderList = new ArrList<Builder>(); //이런게 가능한가?? 된다고 가정하공~ㅋㅋ

      Director director = new Director();

      builderList .add( new SqlDbBuilder();
      builderList .add( new OracleDbBuilder();
      builderList .add( new OleDbBuilder();

      // Construct two products
      director.Construct(builderList );  // director클래스가 있는 이유는 유연성~~,  아래와 같이 바로 코딩해도 상관없겠죠

      // forech ( Builder builder in builderList )
         // Wait for user
      Console.Read();
    }

닷넷 라이브러리의 경우는 리플렉션 에밋(Emit) 기능에서 사용됩니다.
AssemblyBuilder,ModuleBuilder.....각 Builder들이 최종 이루고자 하는 목표는 어셈블리를 동적으로 만들어 내는 것입니다.




[ 적용해본 사례 ]
웹버전 Fusion차트를 생성하는 ChartBuilder

차트객체 생성부는 간단히 추상 팩토리 패턴을 사용했습니다.
더많은 종류의 웹차트도 포괄 할 수 있는 구조가 가능하겠지요.



최종리턴이 BaseChartBuilder인데 Visual Studio가 정확히 Sequential 다이어그램을 만들지 못하는군요.

BaseChartFactory는 간단히 Chart를 생성하는 factory패턴으로 분화 해 갈 수 있게 구조화 했습니다. FusionChart외에 다른 차트도 생성해야 될경우 추상팩토리 패턴을 적용하면됩니다.

그외 클래스들은 Builder패턴에서 제시하는 구조 그대로 구현되어있습니다.
사용 코드는 아래와 같습니다.  Bold체로 된 코드가 주요코드 입니다. good luck...

BaseChartBuilder chartBuilder = null;
string bizCode = Request["BizCode"];
string chartType = Request["ChartType"];
DataTable dataTable = null;


ChartType cType = GenericDefine.ParseEnum<ChartType>(chartType.ToLower());
FusionChart fusionChart = (FusionChart)FusionChartFactory.CreateChart(cType);
using (CommonDataDacNtx db_ntx = new CommonDataDacNtx()) //중간에 처리할 business로직이 없으면 바로 dac호
    dataTable = db_ntx.LoadCategory(1, 1, "");

fusionChart.caption = "싱글축 멀티시리즈~~~~";
fusionChart.subCaption = "서브 캡션";
fusionChart.PYAxisName = "왼쪽축";
fusionChart.SYAxisName = "오른쪽축";
fusionChart.xAxisName="X축이름";
fusionChart.yAxisName="Y축이름";
fusionChart.showAverage = "1";
fusionChart.showvalues = "0";
//fusionChart.palette = "1";
//fusionChart.paletteThemeColor="0000FF";
fusionChart.plotGradientColor = "333333";
chartBuilder = new FusionChartBuilder(fusionChart);

// 가져온 데이타 테이블의 필드를  차트에서 사용할  데이타 필드로 변경하는 작업입니다.
Dictionary<string,string> columnMapping = new Dictionary<string,string>();
columnMapping.Add(ChartDataTableField.seriesName.ToString(), "YYYY");
columnMapping.Add(ChartDataTableField.label.ToString(), "MMM");
columnMapping.Add(ChartDataTableField.value.ToString(), "VALUE");
fusionChart.ChartDataTable = dataTable.MakeFusionChartDataTable(columnMapping);

ChartBuildDirector buildDirector = new ChartBuildDirector();
buildDirector.BuildAll(new List<BaseChartBuilder>() { chartBuilder });

Response.Write( chartBuilder.GetResultChartXml());






더 많은 내용이나 궁금사항은 https://www.facebook.com/groups/480514985402804/