다양한 소스 유형 및 다양한 대상 유형으로 데이터를 가져 오기위한 디자인 패턴


14

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

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

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

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

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


간단하게 유지하십시오.
NoChance

답변:


11

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

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

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

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

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

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


+1, 특히 첫 번째 단락의 경우 (그리고 마지막 단락에서 나와 같은 결론에 도달 한 것이 좋습니다).
Doc Brown

또한 하나의 형식을 다른 형식으로 적용하기 위해 전체 프로젝트의 아키텍처를 염두에 두십시오. 다른 프로젝트에서 누군가가 그 일부만 사용할 수있는 상황을 상상할 수 있습니까? EG 아마도 새로운 데이터 유효성 검사기가 시장에 나와서 SQL 서버에서만 작동합니다. 이제 사용자 정의 XML을 읽고 SQL 서버에 넣고 나머지 단계를 건너 뛰기를 원합니다.
Andyz Smith

이를 용이하게하기 위해, 조각들이 내부 계약을 고수 할뿐만 아니라 조각들 사이의 상호 작용을 정의하는 일련의 계약이 있어야합니다 .
Andyz Smith

@AndyzSmith-코드에서 동일한 문제가 있습니다. 어댑터 패턴을 제외한 모든 코드에 대해 이해했습니다. 전체 프로젝트가 어댑터 패턴의 예라고 말했을 때이를 설명 할 수 있습니까?
gansub

9

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

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


전략 패턴을 사용할 때 개체 (고객, 주소)를 원본에서 대상으로 변환하기위한 별도의 방법을 만들어야한다는 의미입니까? 내가하고 싶은 것은 각 객체를 읽고 변환하고 유효성을 검사 한 다음 목록을 나중에 데이터베이스에 저장할 수 있도록 목록에 넣는 것입니다.
jao

@jao : 글쎄, 만약 당신이 나의 대답을 다시 읽으면, 나의 제안은 "ConvertStrategy"가 아니라 "ReadStrategy"를 만들라는 것을 알 수 있습니다. 따라서 객체 를 읽기 위한 다른 방법 (또는 특정 파일 형식에 따라 프로세스의 추가 부분) 만 작성하면됩니다 .
Doc Brown

7

향후 확장해야 할 가져 오기 유틸리티에 적합한 패턴은 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은 가져온 클래스에서 코드를 사용합니다.

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


전에 MEF에 대해 들어 본 적이 없습니다. 무엇입니까?
jao

2
자세한 설명은 @jao check 링크 를 참조하십시오 . 내 답변에 MEF 자료의 예를 추가했습니다.
Matt

1
이것은 MEF를 시작하는 훌륭한 방법입니다. +1
paqogomez

MEF는 디자인 패턴이 아닌 기술입니다. -1기본 아이디어가 여전히 합리적이며 IImportConverter인터페이스가 지배하는 전략 패턴에 의존하기 때문에 나에게는 아닙니다 .
GETah

0

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

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

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


글쎄, 이것은 당신이 당신 자신의 파일 형식을 자유롭게 사용할 수 있다면 잘 작동하지만 XSLX와 같은 복잡하고 사전 정의 된 형식에 대해서는이 접근법이 실패 할 것입니다. 이는 압축 된 XML 형식의 MS Excel 파일을 의미합니다.
Doc Brown

Excel 파일의 줄을 개체에 매핑 할 수 있지만 해당 방법을 복사하여 XML 및 CSV 리더에 적용해야합니다. 코드를 최대한 깨끗하게 유지하고 싶습니다.
jao

@docBrown-어떻게? 개념적으로 Excel에서 개체를 일련의 셀로 변환하는 것은 XML 문서로 변환하는 것과 실제로 다르지 않습니다.
Telastyn

@ Telastyn : .NET 프레임 워크내장 직렬화 프레임 워크 를 사용 하여 XLSX 형식을 읽을 수 있다고 말 합니까? 이것이 사실이라면 Open XML SDK 또는 NPOI와 같은 라이브러리는 더 이상 사용되지 않습니다.
Doc Brown

@docbrown : 사과합니다. 당신은 맞습니다. 저는 공통 시리얼 라이저 기본 클래스가 없다는 것을 잊고 있습니다. 왜냐하면 제가 작업하는 모든 코드베이스에서 처음으로 수행되는 것 중 하나입니다.
Telastyn
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.