Study/Design Pattern

[Design pattern - 실무편] Excel 빌더 패턴 만들기

v명월v 2019. 6. 13. 22:57

안녕하세요. 명월입니다.

 

이 글은 Builder 패턴을 실무에서 어떻게 사용하는 지 소개하는 글입니다.

 

Builder 패턴의 경우는 보통 Entity 객체를 자동으로 만들어 주는 개념의 패턴입니다.

예를 들면 데이터 베이스에서 데이터를 검색해서 나오는 데이터를 List<Entity>의 형식으로 만드는 것도 빌드 패턴입니다.

 

사실 데이터 베이스의 데이터를 class 객체화 시키는 게 좋은 예이기는 하지만 너무 간단한 예제이기 때문에 저는 Excel의 데이터를 Entity로 내보내는 예제를 만들겠습니다.

 

먼저 Excel의 데이터를 읽어 드리는 NPOI 라이브러리를 사용하는데 NPOI의 설명은 다음 링크를 참조해 주세요.

[C#] NPOI를 이용하여 Excel를 읽어드리고 다시 출력하기 - https://nowonbun.tistory.com/400?category=507116

 

다음의 엑셀 데이터를 읽어서 Entity라는 클래스에 List로 만들 생각입니다.

먼저 데이터를 담을 Entity 클래스를 만듭니다.

class Entity
{
  // Excel의 1열
  public int Index { get; set; }
  // Excel의 2열
  public String Data1 { get; set; }
  // Excel의 3열
  public String Data2 { get; set; }
}

그리고 Excel로 부터 데이터를 가져와서 위 Entity클래스로 변환 시킬 빌더를 만듭니다.

class ExcelBuilder
{
  private IWorkbook workbook;
  public ExcelBuilder(String path)
  {
    this.workbook = GetWorkbook(path);
  }
  // 빌드할 시트 인덱스를 받는다.
  public List<Entity> Build(int sheetIndex)
  {
    List<Entity> ret = null;
    var sheet = this.workbook.GetSheetAt(sheetIndex);
    // 첫번째 행은 타이틀이니 생략한다.
    int rowindex = 1;
    while (true)
    {
      // 두번째 행부터 데이터를 가져온다.
      var row = sheet.GetRow(rowindex++);
      // 행이 Null이 나오면 데이터 끝으로 기준한다.
      if (row == null)
      {
        break;
      }
      // 행의 첫번째 열이 Null이면 데이터 끝으로 기준한다.
      if(row.GetCell(0) == null)
      {
        break;
      }
      // Flyweight 패턴으로 데이터가 하나도 없으면 null를 내보낸다.
      if (ret == null)
      {
        ret = new List<Entity>();
      }
      // 데이터를 읽어서 Entity 클래스를 생성한다.
      var entity = new Entity();
      entity.Index = (int)row.GetCell(0).NumericCellValue;
      entity.Data1 = row.GetCell(1)?.StringCellValue;
      entity.Data2 = row.GetCell(2)?.StringCellValue;
      // 리스트에 넣는다.
      ret.Add(entity);
    }
    return ret;
  }
  // 엑셀 파일을 읽어 드리는 함수
  public IWorkbook GetWorkbook(string filename)
  {
    using (var stream = new FileStream(filename, FileMode.Open, FileAccess.Read))
    {
      return new XSSFWorkbook(stream);
    }
  }
}

다음은 실행 부분입니다.

class Program
{
  static void Main(string[] args)
  {
    // 엑셀을 읽어드린다.
    var builder = new ExcelBuilder(System.Environment.CurrentDirectory + "\\TestData.xlsx");
    // Entity를 만든다.
    var list = builder.Build(0);

    // null이 아니면
    if(list != null)
    {
      // 결과 출력
      // 1 Test1-1 Test2-1
      // 2 Test1 - 2 Test2 - 2
      // 3 Test1 - 3 Test2 - 3
      // 4 Test1 - 4 Test2 - 4
      // 5 Test1 - 5 Test2 - 5
      foreach (var item in list)
      {
        Console.WriteLine("{0} {1} {2}", item.Index, item.Data1, item.Data2);
      }
    }
    Console.WriteLine("Press any key...");
    Console.ReadKey();
  }
}

소스를 보면 엄청 간단한 것처럼 보입니다. 그러나 실제 업무를 가보면 패턴 적용을 안하고 실행 흐름대로 Excel을 읽어드리는 부분을 만드는 분이 꽤 있습니다.

실제로 그런 소스를 보면 엄청 복잡합니다. 사실 그게 소스가 복잡한게 아니라 패턴 적용이 안되서 엄청 지저분 해 보이는 것입니다.

이렇게 패턴 적용을 하면 소스가 정말 단순해 보이고 명확하게 보입니다.


정말 잘 만든 소스는 정말 프로그램이 쉬워 보이도록 만든 소스라고 저는 믿고 있습니다.

 

여기까지 Excel builder 패턴에 대한 설명이었습니다.

 

궁금한 점이나 잘못된 점이 있으면 댓글 부탁드립니다.