여러 내보내기 유형을위한 견고한 아키텍처를 설계하십니까?


10

디자인중인 다음 기능에 대한 패턴 또는 아키텍처 지침을 찾고 있습니다. 기본적으로 여러 내보내기 대상이있는 내보내기 기능이며 새 내보내기 대상을 연결하는 데 많은 핵심 변경이 필요하지 않은 경우 일반화 할 수있는 방법을 찾고 있습니다. 내보내기 대상을 사용하면 PDF, PowerPoint 프레젠테이션, Word 문서, RSS 등 다양한 유형의 출력을 간단히 언급하고 있습니다. JSON 및 XML로 표시되는 기본 데이터 세트가 있습니다. 이 데이터는 이미지 (임의의 숫자 또는 내보내기 유형 (예 : PNG, JPG, GIF 등) 사용), 그래프, 텍스트 표현, 표 등을 구성하는 데 사용됩니다.

추가 렌더링 대상 추가를 처리하는 렌더링 또는 레이아웃 엔진으로 모든 렌더링 및 레이아웃을 추상화하는 방법을 찾으려고합니다. 이에 접근하는 방법에 대한 도움 / 제안 / 자원은 대단히 감사하겠습니다. 미리 감사드립니다.

내가 달성하려는 것을 그림으로 표현하십시오.

여기에 이미지 설명을 입력하십시오


지금까지 시도한 내용을 설명 할 수 있습니까? 레이아웃 엔진의 요구 사항 (책임)은 무엇입니까? 예를 들어 페이지 매김 및 페이지 크기 선택을 처리 할 것으로 예상됩니까?
rwong

XML / JSON 데이터를 사용하여 동일한 출력 실행에서 여러 출력 유형을 작성할 수 있습니까? 즉, XML 데이터가 PDF 문서에서 이미지 및 테이블 및 그래프를 생성합니까? 또는 XML / JSON 데이터를 사용하여 PDF 문서에 대한 테이블 또는 그래프를 작성할 수 있습니까?
깁슨

이것은 xkcd.com/927 에 관한 것입니다 -왜 바퀴를 재발 명하려고합니까? DocBook, Markdown / pandoc 등이 이미 존재합니다 ...
Deer Hunter

답변:


2

저에게는 갈 길은 인터페이스와 팩토리입니다. 하나는 다양한 클래스가 숨길 수있는 인터페이스에 대한 참조를 반환합니다. 실제 grunt 작업을 수행하는 클래스는 모두 팩토리에 등록해야하므로 주어진 매개 변수 세트를 인스턴스화 할 클래스를 알 수 있습니다.

참고 : 인터페이스 대신 추상 기본 클래스를 사용할 수도 있지만 단일 상속 언어의 경우 단일 기본 클래스로 제한한다는 단점이 있습니다.

TRepresentationType = (rtImage, rtTable, rtGraph, ...);

Factory.RegisterReader(TJSONReader, 'json');
Factory.RegisterReader(TXMLReader, 'xml');

Factory.RegisterWriter(TPDFWriter, 'pdf');
Factory.RegisterWriter(TPowerPointWriter, 'ppt');
Factory.RegisterWriter(TWordWriter, 'doc');
Factory.RegisterWriter(TWordWriter, 'docx');

Factory.RegisterRepresentation(TPNGImage, rtImage, 'png');
Factory.RegisterRepresentation(TGIFImage, rtImage, 'gif');
Factory.RegisterRepresentation(TJPGImage, rtImage, 'jpg');
Factory.RegisterRepresentation(TCsvTable, rtTable, 'csv');
Factory.RegisterRepresentation(THTMLTable, rtTable, 'html');
Factory.RegisterRepresentation(TBarChart, rtTGraph, 'bar');
Factory.RegisterRepresentation(TPieChart, rtTGraph, 'pie');

코드는 가장 친숙한 언어이므로 Delphi (파스칼) 구문으로되어 있습니다.

모든 구현 클래스가 팩토리에 등록되면 해당 클래스의 인스턴스에 대한 인터페이스 참조를 요청할 수 있어야합니다. 예를 들면 다음과 같습니다.

Factory.GetReader('SomeFileName.xml');
Factory.GetWriter('SomeExportFileName.ppt');
Factory.GetRepresentation(rtTable, 'html');

TXMLReader 인스턴스에 대한 IReader 참조를 리턴해야합니다. TPowerPointWriter 인스턴스에 대한 IWriter 참조 및 THTMLTable 인스턴스에 대한 IRepresentation 참조

이제 모든 렌더링 엔진은 모든 것을 하나로 묶습니다.

procedure Render(
  aDataFile: string; 
  aExportFile: string;
  aRepresentationType: TRepresentationType;
  aFormat: string;
  );
var
  Reader: IReader;
  Writer: IWriter;
  Representation: IRepresentation;
begin
  Reader := Factory.GetReaderFor(aDataFile);
  Writer := Factory.GetWriterFor(aExportFile);
  Representation := Factory.GetRepresentationFor(aRepresentationType, aFormat);

  Representation.ConstructFrom(Reader);
  Writer.SaveToFile(Representation);
end;

IReader 인터페이스는 IRepresentation 구현자가 데이터 표현을 구성하는 데 필요한 데이터를 읽는 메소드를 제공해야합니다. 마찬가지로 IRepresentation은 IWriter 구현자가 데이터 표현을 요청 된 내보내기 파일 형식으로 내보내는 데 필요한 메소드를 제공해야합니다.

파일의 데이터가 본질적으로 테이블 형식이라고 가정하면 IReader 및 지원 인터페이스는 다음과 같습니다.

IReader = interface(IInterface)
  function MoveNext: Boolean;
  function GetCurrent: IRow;
end;

IRow = interface(IInterface)
  function MoveNext: Boolean;
  function GetCurrent: ICol;
end;

ICol = interface(IInterface)
  function GetName: string;
  function GetValue: Variant;
end;

그런 다음 테이블을 반복하면 문제가됩니다.

while Reader.MoveNext do
begin
  Row := Reader.GetCurrent;
  while Row.MoveNext do
  begin
    Col := Row.GetCurrent;
    // Do something with the column's name or value
  end;
end;

표현은 본질적으로 이미지, 그래프 및 텍스트 일 ​​수 있으므로 IRepresentation은 아마도 구성된 테이블을 탐색하기 위해 IReader와 유사한 메소드를 가지고 있으며 이미지 및 그래프를 예를 들어 바이트 스트림으로 가져 오는 메소드를 가지고 있습니다. 내보내기 대상에 필요한대로 테이블 값과 이미지 / 그래프 바이트를 인코딩하는 것은 IWriter 구현 자에 달려 있습니다.


1

아키텍처에 대해 더 많은 정보가 필요하다는 데 동의하지만 동일하게 동작하는 다른 종류의 객체를 만드는 가장 간단한 방법 (즉, 모든 객체가 출력을 생성 함)은 팩토리 패턴을 사용하는 것입니다. 더 많은 정보는 여기에

팩토리 메소드 패턴은 팩토리의 개념을 구현하고 작성 될 정확한 클래스의 오브젝트를 지정하지 않고 오브젝트 (제품) 작성 문제를 처리하기위한 오브젝트 지향 작성 디자인 패턴입니다. 이 패턴의 본질은 "객체를 만들기위한 인터페이스를 정의하지만 인터페이스를 구현하는 클래스가 인스턴스화 할 클래스를 결정하게합니다. Factory 메소드는 클래스가 서브 클래스에 대한 인스턴스화를 지연시킬 수 있도록합니다." 위키 백과에서


1
나는 그것보다 조금 더 관련이 있다고 생각합니다. 예를 들어, 다이어그램의 라인을 따라 데이터를 전달하는 데 어떤 프로토콜이 사용됩니까? 렌더링 / 레이아웃 엔진에 공통적 인 데이터 표현이있을 수 있습니까? 아니면 해당 엔진이 다이어그램의 각 줄에 하나씩 완벽하게 사용자 정의 된 방법의 팩토리입니까?
Robert Harvey

확실하지 않은 점이 여기에 있습니다. 다이어그램에서 라인을 통신하기 위해 프로토콜을 사용해야하는 경우 내보내기를 생성하기 위해 일련의 서비스에 의존하고 있다고 생각합니다 (이 경우 soa / integration 패턴을보고 싶습니다). 이것이 사실이더라도 솔루션은 공장을 사용할 수있을만큼 유연하고 강력합니다. 어쩌면 당신이하고 싶은 일은 XML 데이터를 수신하는 방법과 JSON 데이터를위한 방법의 두 가지 방법이있는 변환기 인터페이스를 만드는 것입니다. 둘 다에 대한 반환 개체는 변환 된 개체가됩니다. 그렇게하면 원하는대로 조립할 수 있습니다.
Orposuser

실제로 헤더에는 내용 (gif, pdf, html)과 전송 (로컬 파일, http-response-item)에 관한 두 가지 질문이 있습니다. @Orposuser (+1) 답변을 확장하려면 : 팩토리를 사용하여 http-response에 대해 쉽게 단위 테스트를 쉽게하고 쉽게 렌더링 할 수있는 스트림을 만듭니다.
k3b

0

이런 식으로 끝날 수 있습니다.

두 공장은 다음을 기반으로합니다.

1-입력 유형 (Json / XML)을이 데이터를 이미지 / 그래프로 변환하는 구체적인 구현으로 변환

2-출력을 워드 문서 / PDF 문서로 렌더링하는 방법을 결정하기위한 두 번째 팩토리

다형성은 렌더링 된 모든 데이터에 공통 인터페이스를 사용합니다. 따라서 이미지 / 테이블을 간편한 인터페이스로 이동할 수 있습니다.

1-JSON / XML 데이터를 구체적인 구현으로 변환하는 팩토리 :

public enum DataTypeToConvertTo
{
    Image,
    Table,
    Graph,
    OtherData
}

public interface IDataConverter
{
    IConvertedData ConvertJsonDataToOutput(Json jsonData);
    IConvertedData ConvertXmlDataToOutput(XDocument xmlData);
}

public abstract class DataConverter : IDataConverter
{
    public DataConverter()
    {

    }

    public abstract IConvertedData ConvertDataToOutput(string data);
}

아래의 팩토리에서는 xml 데이터 또는 Json 데이터를 올바른 콘크리트 유형으로 변환 할 수 있습니다.

public class DataConverterFactory
{
    public static IDataConverter GetDataConverter(DataTypeToConvertTo dataType)
    {
        switch(dataType)
        {
            case DataTypeToConvertTo.Image:
                return new ImageDataConverter();
            case DataTypeToConvertTo.Table:
                return new TableDataConverter();
            case DataTypeToConvertTo.OtherData:
                return new OtherDataConverter();
            default:
                throw new Exception("Unknown DataTypeToConvertTo");
        }
    }
}

구체적인 구현은 데이터를 관련 유형으로 변환하는 모든 무거운 작업을 수행합니다. 또한 데이터를 다형성에 사용되는 IConvertedData 인터페이스로 변환합니다.

public sealed class ImageDataConverter : DataConverter
{
    public ImageDataConverter()
        : base()
    {

    }

    public override IConvertedData ConvertJsonDataToOutput(Json jsonData)
    {
        var convertedData = new ImageConvertedData();
        //Logic to convert to necessary datatype

        return convertedData;
    }

    public override IConvertedData ConvertXmlDataToOutput(XDocument xmlData)
    {
        var convertedData = new ImageConvertedData();
        //Logic to convert to necessary datatype

        return convertedData;
    }
}

public sealed class TableDataConverter : DataConverter
{
    public TableDataConverter()
        : base()
    {

    }

    public override IConvertedData ConvertJsonDataToOutput(Json jsonData)
    {
        var convertedData = new TableConvertedData();
        //Logic to convert to necessary datatype

        return convertedData;
    }

    public override IConvertedData ConvertXmlDataToOutput(XDocument xmlData)
    {
        var convertedData = new ImageConvertedData();
        //Logic to convert to necessary datatype

        return convertedData;
    }
}

public sealed class OtherDataConverter : DataConverter
{
    public OtherDataConverter()
        : base()
    {

    }

    public override IConvertedData ConvertJsonDataToOutput(Json jsonData)
    {
        var convertedData = new OtherConvertedData();
        //Logic to convert to necessary datatype

        return convertedData;
    }

    public override IConvertedData ConvertXmlDataToOutput(XDocument xmlData)
    {
        var convertedData = new OtherConvertedData();
        //Logic to convert to necessary datatype

        return convertedData;
    }
}

코드가 확장되면 필요에 따라 이러한 구현을 추가 할 수 있습니다.

IConvertedData 인터페이스를 사용하면 단일 유형을 다음 단계로 전달할 수 있습니다. 참고 : 여기서 공백을 반환하지 않을 수 있습니다. 이미지의 경우 바이트 [] 또는 WordDocument의 경우 OpenXml 문서 일 수 있습니다. 필요에 따라 조정하십시오.

public interface IConvertedData
{
    void RenderToPdf();
    void RenderToDocument();
    void RenderToOhter();
    void RenderToPowerPoint();
}

다형성 :

데이터를 관련 출력 유형으로 변환하는 데 사용됩니다. 즉, 이미지 데이터의 PDF 렌더링은 PowerPoint의 렌더링 이미지 데이터와 다를 수 있습니다.

public sealed class ImageConvertedData : IConvertedData
{
    public void RenderToPdf()
    {
        //Logic to render Images
    }

    public void RenderToDocument()
    {
        //Logic to render Images
    }
}
public sealed class TableConvertedData : IConvertedData
{
    public void RenderToPdf()
    {
        //Logic to render Document
    }

    public void RenderToDocument()
    {
        //Logic to render Document
    }
}

public sealed class OtherConvertedData : IConvertedData
{
    public void RenderToPdf()
    {
        //Logic to render PDF
    }

    public void RenderToDocument()
    {
        //Logic to render PDF
    }
}

2-출력 형식을 결정하는 팩토리 :

public enum ExportOutputType
{
    PDF,
    PowerPoint,
    Word,
    Other
}

public interface IOutputExporter
{
    void ExportData(IConvertedData data);
}


public class OutputExporterFactory
{
    public static IOutputExporter GetExportOutputType(ExportOutputType exportOutputType)
    {
        switch(exportOutputType)
        {
            case ExportOutputType.PDF:
                return new OutputExporterPdf();
            case ExportOutputType.PowerPoint:
                return new OutputExporterPowerPoint();
            case ExportOutputType.Other:
                return new OutputExporterOther();
            default:
                throw new Exception ("Unknown ExportOutputType");
        }
    }
}

각각의 구체적인 구현은 내보내기가 IConvertedData 구현으로 되돌아 오는 방식을 마스크하는 공통 메소드를 노출합니다.

public abstract class OutputExporter : IOutputExporter
{
    //Other base methods...
    public virtual void ExportData(IConvertedData data)
    {

    }
}

public sealed class OutputExporterPdf : OutputExporter
{
    public OutputExporterPdf()
        : base()
    {

    }

    public override void ExportData(IConvertedData data)
    {
        //Functionality to Export to Pdf
        data.RenderToPdf();
    }
}

public sealed class OutputExporterPowerPoint : OutputExporter
{
    public OutputExporterPowerPoint()
        : base()
    {

    }

    public override void ExportData(IConvertedData data)
    {
        //Functionality to Export to PowerPoint
        data.RenderToPowerPoint();
    }
}

public sealed class OutputExporterOther : OutputExporter
{
    public OutputExporterOther()
        : base()
    {

    }

    public override void ExportData(IConvertedData data)
    {
        //Functionality to Export to PowerPoint
        data.RenderToOhter();
    }
}

이 모든 샘플 클라이언트는 다음과 같습니다.

public class Client
{
    public Client()
    {

    }
    public void StartExportProcess(XDocument data)
    {
        IDataConverter converter = DataConverterFactory.GetDataConverter(DataTypeToConvertTo.Graph);

        IConvertedData convertedData = converter.ConvertXmlDataToOutput(data);


        IOutputExporter exportOutputer = OutputExporterFactory.GetExportOutputType(ExportOutputType.PDF);
        exportOutputer.ExportData(convertedData);
    }
}

0

https://ergebnisse.zensus2011.de/?locale=ko 여기에서 비슷한 문제를 해결했습니다 . pdf, excel, web과 같은 다른 형식으로 내보낼 수있는 "테이블"과 "그래프"가 있습니다. 우리는 각 객체를 클래스를 생성하고 읽을 수있는 인터페이스가있는 자체 Java 클래스로 렌더링하도록 지정했습니다. 귀하의 경우 각 객체마다 2 개의 구현 (xml, json)이 구현되고 4 개의 렌더링 (읽기)이 구현됩니다.

예 : 테이블에 대한 몇 가지 클래스가 필요합니다. 클래스 테이블 (테이블 구조, 유효성 검증 및 컨텐츠 처리) 인터페이스 CreateTable (테이블 데이터, 셀, 범위, 컨텐츠 제공) 인터페이스 ReadTable (모든 데이터에 대한 getter)

아마도 인터페이스 (또는 하나만)가 필요하지는 않지만 테스트에서 특히 유용한 분리를 항상 제공한다고 생각합니다.


0

당신이 찾고있는 것은 전략 패턴 이라고 생각합니다 . 원하는 형식으로 데이터를 출력하는 다양한 클래스가 있으며 런타임에 적절한 클래스를 선택하기 만하면됩니다. 새로운 형식을 추가하는 것은 필요한 인터페이스를 구현하는 다른 클래스를 추가하는 것만 큼 간단해야합니다. Java를 사용하여 Spring을 사용하여 종종 형식 유형별로 키가 지정된 변환기 맵을 유지 관리하기 위해이 작업을 자주 수행했습니다.

다른 사람들이 언급했듯이 이것은 일반적으로 모든 클래스가 동일한 인터페이스를 구현하거나 동일한 기본 클래스의 하위 클래스로 구현하고 팩토리를 통해 구현을 선택하여 수행됩니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.