다양한 소스 유형 및 다양한 대상 유형으로 데이터를 가져 오기위한 디자인 패턴 (C #로)를 디자인하고 빌드해야합니다. 다양한

다음을 처리 할 수있는 가져 오기 스크립트 (C #로)를 디자인하고 빌드해야합니다.

  • 다양한 소스 (XML, XSLX, CSV)에서 데이터 읽기
  • 데이터 확인
  • 다양한 객체 유형 (고객, 주소)에 데이터 쓰기

데이터는 여러 소스에서 제공되지만 소스는 항상 하나의 가져 오기 형식 (csv, xml, xslx)을 갖습니다. 가져 오기 형식은 소스마다 다를 수 있습니다. 향후 새로운 가져 오기 형식이 추가 될 수 있습니다. 대상 객체 유형은 항상 동일합니다 (고객, 주소 등).

나는 제네릭 사용에 대해 생각하고 공장 패턴에 대해 읽었지만이 분야에서 꽤 큰 멍청한 사람이므로 조언을 환영합니다.

이 문제를 해결하기위한 적절한 디자인 패턴은 무엇입니까?



답변

당신은 멋진 개념으로 너무 빨리 가고 있었다. 제네릭-사례를 볼 때 사용하지만 걱정하지 마십시오. 팩토리 패턴-아직 너무 많은 유연성과 혼란이 추가되었습니다.

간단하게 유지하십시오. 기본 관행을 사용하십시오.

  1. XML에 대한 읽기, CSV에 대한 읽기를 수행하는 것의 공통점을 상상해보십시오. 다음 레코드, 다음 줄과 같은 것들. 새로운 형식이 추가 될 수 있으므로, 결정될 형식이 알려진 형식과 공통점이 있다고 생각하십시오. 이 공통성을 사용하고 ‘인터페이스’또는 모든 형식을 준수해야하는 계약을 정의하십시오. 공통점을 준수하지만 모두 특정 내부 규칙을 가질 수 있습니다.

  2. 데이터의 유효성을 검사하려면 새로운 또는 다른 유효성 검사기 코드 블록을 쉽게 연결할 수있는 방법을 제공하십시오. 다시 말하지만 특정 종류의 데이터 구성을 담당하는 각 유효성 검사기가 계약을 준수하는 인터페이스를 정의하십시오.

  3. 데이터 구성을 만들려면 제안 된 출력 개체를 무엇보다 설계 한 사람이 제한을받습니다. 데이터 객체의 다음 단계가 무엇인지 파악하고 최종 용도를 알고 최적화 할 수 있습니까? 예를 들어 객체가 대화 형 응용 프로그램에서 사용될 예정이라는 것을 알고 있다면 ‘개요’또는 객체 수 또는 다른 종류의 파생 정보를 제공하여 해당 앱 개발자에게 도움이 될 수 있습니다.

나는 이것들 대부분이 템플릿 패턴이나 전략 패턴이라고 말합니다. 전체 프로젝트는 어댑터 패턴입니다.


답변

분명한 것은 전략 패턴 을 적용하는 것입니다 . 일반적인 기본 클래스를 가지고 ReadStrategy각각의 입력 형식과 같은 서브 클래스 XmlReadStrategy, CSVReadStrategy등이 당신이에서 인증 할 처리 및 출력 처리에서 독립적으로 가져 오기 처리를 변경할 수 있습니다.

세부 사항에 따라 가져 오기의 대부분을 일반으로 유지하고 입력 처리의 일부만 교환 할 수도 있습니다 (예 : 하나의 레코드 읽기). 이로 인해 Template Method pattern 이 나타날 수 있습니다 .


답변

향후 확장해야 할 가져 오기 유틸리티에 적합한 패턴은 MEF를 사용하는 것입니다. 게으른 목록에서 필요한 변환기를 즉시로드하여 메모리 사용을 낮게 유지하고 속성으로 장식 된 MEF 가져 오기를 작성할 수 있습니다. 수행하려는 가져 오기에 적합한 변환기를 선택하고 다른 가져 오기 클래스를 쉽게 분리 할 수있는 방법을 제공합니다.

각 MEF 파트는 가져 오기 파일의 행을 출력 데이터로 변환하거나 기본 기능으로 기본 클래스를 대체하는 일부 표준 메소드를 사용하여 가져 오기 인터페이스를 충족하도록 빌드 할 수 있습니다.

MEF는 플러그인 아키텍처를 만들기위한 프레임 워크입니다. Outlook과 Visual Studio의 구축 방식은 VS의 모든 확장 기능이 MEF 파트입니다.

MEF (Managed Extensability Framework) 앱을 빌드하려면 System.ComponentModel.Composition

변환기가 수행 할 작업을 지정하기위한 인터페이스 정의

public interface IImportConverter
{
    int UserId { set; }
    bool Validate(byte[] fileData, string fileName, ImportType importType);
    ImportResult ImportData(byte[] fileData, string fileName, ImportType importType);
}

가져 오려는 모든 파일 형식에 사용할 수 있습니다.

클래스가 “내보내기”대상을 정의하는 속성을 새 클래스에 추가

[Export(typeof(IImportConverter))]
[MyImport(ImportType.Address, ImportFileType.CSV, "4eca4a5f-74e0")]
public class ImportCSVFormat1 : ImportCSV, IImportConverter
{
 ...interface methods...
}

이것은 CSV 파일 (특정 형식 : Format1)을 가져올 클래스를 정의하고 MEF 내보내기 속성 메타 데이터를 설정하는 사용자 정의 속성을 갖습니다. 가져 오려는 각 형식 또는 파일 형식에 대해이 작업을 반복하십시오. 다음과 같은 클래스로 사용자 정의 속성을 설정할 수 있습니다.

[MetadataAttribute]
[AttributeUsage(AttributeTargets.All, AllowMultiple = false)]
public class ImportAttribute : ExportAttribute
{
    public ImportAttribute(ImportType importType, ImportFileType fileType, string customerUID)
        : base(typeof(IImportConverter))
    {
        ImportType = importType;
        FileType = fileType;
        CustomerUID = customerUID;
    }

    public ImportType ImportType { get; set; }
    public ImportFileType FileType { get; set; }
    public string CustomerUID { get; set; }
}

실제로 MEF 변환기를 사용하려면 변환 코드가 실행될 때 생성 한 MEF 부품을 가져와야합니다.

[ImportMany(AllowRecomposition = true)]
protected internal Lazy<IImportConverter, IImportMetadata>[] converters { get; set; }
AggregateCatalog catalog = new AggregateCatalog();

catalog 폴더에서 부품을 수집하며 기본값은 앱 위치입니다.

converters 가져온 MEF 부품의 게으른 목록입니다.

그런 다음 어떤 종류의 파일을 변환 하려는지 알고 ( importFileTypeimportType) 가져온 부품 목록에서 변환기를 가져옵니다.converters

var tmpConverter = (from x in converters
                    where x.Metadata.FileType == importFileType
                    && x.Metadata.ImportType == importType
                    && (x.Metadata.CustomerUID == import.ImportDataCustomer.CustomerUID)
                    select x).OrderByDescending(x => x.Metadata.CustomerUID).FirstOrDefault();

if (tmpConverter != null)
{
     var converter = (IImportConverter)tmpConverter.Value;
     result = converter.ImportData(import.ImportDataFile, import.ImportDataFileName, importType);
....
}

에 대한 호출 converter.ImportData은 가져온 클래스에서 코드를 사용합니다.

많은 코드처럼 보일 수 있으며 머리를 돌리는 데 시간이 걸릴 수 있지만 새로운 변환기 유형을 추가 할 때 매우 유연하며 런타임 중에 새 유형을 추가 할 수도 있습니다.


답변

이 문제를 해결하기위한 적절한 디자인 패턴은 무엇입니까?

C # 관용구에는 내장 직렬화 프레임 워크를 사용하여이를 수행합니다. 메타 데이터를 사용하여 개체에 주석을 달고 해당 주석을 사용하여 데이터를 추출하여 올바른 양식에 넣거나 그 반대의 다른 직렬 변환기를 인스턴스화합니다.

Xml, JSON 및 이진 형식이 가장 일반적이지만 다른 패키지가 이미 멋진 패키지 형식으로 존재하더라도 놀라지 않을 것입니다.


답변