2009-08-12 4 views
0

필자는 다양한 데이터베이스/테이블의 엔터프라이즈 데이터를 레거시 응용 프로그램에서 사용하기 위해 특정 형식의 플랫 파일로 변환해야하는 유지 관리 응용 프로그램을 보유하고 있습니다.플랫 파일 변환을위한 데이터 모델 설계 ... 델리게이트 또는 상속?

public class StatusCode 
{ 
    public String Id { get; set; } 
    public Char Level { get; set; } 
    public String Description { get; set; } 
} 

데이터 원본에서 이러한 레코드의 일부 또는 전체를 선택합니다. 그리고 각 엔티티를 파일의 한 줄로 매핑해야하는데, 데이터를 조정해야 할 수도 있습니다 (패딩, 변환 또는 처리 null).

public delegate String MapEntity<T>(T entity); 
public MapEntity<StatusCode> MapStatusCode = delegate(StatusCode entity) 
{ 
    return String.Format("{0},{1},{2}", 
     entity.Id.PadLeft(3, '0'), 
     entity.Level == 'S' ? 0 : 1, 
     entity.Description ?? "-"); 
} 

질문은 어떻게 변환 클래스를 작성합니까? 매핑 대리자를 사용하는 "DefaultFileCreator"를 제공합니까?

public interface IFileCreator 
{ 
    Byte[] Create<T>(MapEntity<T> map, IEnumerable<T> entities); 
} 

public class DefaultFileCreator : IFileCreator 
{ 
    public Byte[] Create<T>(MapEntity<T> map, IEnumerable<T> entities) 
    { 
     StringBuilder sb = new StringBuilder(); 
     foreach (T entity in entities) 
      sb.AppendLine(map(entity)); 

     return Encoding.Default.GetBytes(sb.ToString()); 
    } 
} 

... 
fileCreator.Create(MapStatusCode, repository<StatusCode>.FindAll()); 
... 

이 솔루션을 사용하면 어디에서 어떤 범위에서 매핑 대리자를 유지해야하는지 걱정됩니다. 그리고 내가 어떻게해야하는지 알지 못하고 전화하는 방법은 T입니다.

또는 인터페이스를 변경하고 구체적인 클래스에서 매핑을 요구합니까?

public interface IFileCreator<T> 
{ 
    Byte[] Create(IEnumerable<T> entities); 
} 

public abstract class FileCreator : IFileCreator<T> 
{ 
    protected abstract String Map(T entity); 

    public Byte[] Create(IEnumerable<T> entities) 
    { 
     StringBuilder sb = new StringBuilder(); 
     foreach (T entity in entities) 
      sb.AppendLine(Map(entity)); 

     return Encoding.Default.GetBytes(sb.ToString()); 
    } 
} 

public class StatusCodeFile : FileCreator<StatusCode> 
{ 
    public override String Map(T entity) 
    { 
     return String.Format("{0},{1},{2}", 
      entity.Id.PadLeft(3, '0'), 
      entity.Level == 'S' ? 0 : 1, 
      entity.Description ?? "-"); 
    } 
} 

이 솔루션은 구체적인 클래스로 폭발하지만 매핑 위임자만큼 얇습니다. 그리고 IFileCreator<T>과 공장에서 일하는 것이 더 편합니다. (다시 필요할 경우에만).

나는 어떤 기본 클래스가 StringBuilder 루프와 Byte[] 인코딩으로 유용하다고 가정하고 있습니다. 구체적인 클래스가 (추상 메소드를 호출하는 대신) 기본 클래스에 델리게이트 속성을 설정해야합니까? 메서드에 type 매개 변수를 유지해야합니까 (기본/콘크리트 클래스에 어떤 영향을 미칩니 까?).

나는 어떤 해결책이있어. 나의 주요 목표는 유지 보수의 용이성이다. 나는 지금 12 모델/파일을 가지고 있으며 이것은 21까지 증가 할 수 있습니다. 임의의 머리말/꼬리말을 모든 파일에 삽입해야한다는 요구가있을 수 있습니다. (그래서 나는 overrideable 기본 클래스 메소드 인 Map을 좋아합니다.)

답변

0

몇 가지 변환을 작성 했으므로 이제는 클래스 별 매핑 방식으로 기울이고 있습니다. 필자는 가짜 모델에 대해 단위 테스트를 실행하여 파일이 제대로 빌드되었는지 확인해야합니다 (알려진 양호한 샘플 파일에 대해 테스트).

저는 매핑 위임자가 자신이 속한 "워크 플로"클래스 (모델/파일 당 하나의 "워크 플로")에 대한 비공개로 만들고 있습니다. 그것들을 단위 테스트에 공개하거나 중간 파일 내용을 출력해야합니다 (작업 흐름은 완성 된 파일을 데이터 저장소에 저장합니다).

클래스 당 매핑은 훨씬 더 테스트 가능하고 분해 가능해 보입니다.

+0

각 구체적인 클래스 MapEntity (대리자)에서 추상 속성을 재정의하는 것도 고려하고 있습니다. 메소드 Map (T)를 오버라이드 (override)하는 것과 같은 효과. 다른 모양. –

1

실제로 가능한 매핑마다 구체적인 하위 클래스를 만들어야합니까? 아마도 XML 파일 (또는 데이터베이스)을 사용하여 각 종류의 파일 형식/내용을 설명하는 것이 가능할 수 있습니다. 그런 다음 "FileType"키를 사용하고 XML의 형식 정보를 사용하여 해당 FileType에 대한 파일을 작성하는 방법을 결정하는 단일 클래스가 있습니다.

+0

매핑 위임을 사용하는 것과 동일한 솔루션 (의도적으로)이라고 생각합니다. –

+0

@ajmastrean - 이제 좀 더 자세히 살펴 보겠습니다. "T"가 무엇인지 알지 못하면 어떻게 할 것인가? 모든 속성을 얻기 위해 리플렉션을 사용하기 때문에 실제로 어쨌든 객체의 유형을 알 필요가 없습니다. –

관련 문제