Thiết kế một kiến ​​trúc mạnh mẽ cho nhiều loại xuất khẩu?


10

Tôi đang tìm kiếm các mẫu hoặc hướng dẫn kiến ​​trúc cho một tính năng sắp tới mà tôi đang thiết kế. Về cơ bản, đây là một tính năng xuất với nhiều mục tiêu xuất khẩu và tôi đang tìm cách để làm cho nó đủ chung chung khi việc cắm vào các mục tiêu xuất khẩu mới không đòi hỏi nhiều thay đổi cốt lõi. Theo mục tiêu xuất khẩu, tôi chỉ đơn giản đề cập đến các loại đầu ra khác nhau, cho dù đó là PDF, bản trình bày PowerPoint, tài liệu Word, RSS, v.v. Tôi có một bộ dữ liệu cơ bản, được trình bày trong JSON và XML. Dữ liệu này được sử dụng để xây dựng hình ảnh (sử dụng bất kỳ số lượng hoặc loại xuất nào [ví dụ: PNG, JPG, GIF, v.v.), biểu đồ, biểu diễn văn bản, bảng, v.v.

Tôi đang cố gắng tìm cách trừu tượng hóa tất cả kết xuất và bố cục thành một loại công cụ kết xuất hoặc bố cục nào đó để xử lý việc thêm các mục tiêu xuất khác. Bất kỳ trợ giúp / đề xuất / tài nguyên nào về cách tiếp cận này sẽ được đánh giá rất cao. Cảm ơn trước.

Đối với một đại diện hình ảnh của những gì tôi đang cố gắng để đạt được.

nhập mô tả hình ảnh ở đây


Bạn có thể mô tả những gì bạn đã cố gắng cho đến nay? Các yêu cầu (trách nhiệm) của công cụ bố trí là gì? Ví dụ, dự kiến ​​sẽ xử lý phân trang và lựa chọn kích thước trang?
rwong

Dữ liệu XML / JSON có thể được sử dụng để tạo nhiều loại đầu ra trên cùng một lần chạy đầu ra không, tức là dữ liệu XML của bạn tạo ra Hình ảnh và Bảng và Đồ thị trong tài liệu PDF? Hoặc chỉ có thể sử dụng dữ liệu XML / JSON để tạo Bảng hoặc Biểu đồ cho tài liệu PDF?
Gibson

Đây là tất cả về xkcd.com/927 - tại sao bạn lại cố gắng phát minh lại bánh xe? DocBook, Markdown / pandoc, v.v. đã tồn tại ...
Deer Hunter

Câu trả lời:


2

Đối với tôi, con đường để đi sẽ là các giao diện và một Nhà máy. Một lớp trả về các tham chiếu đến các giao diện phía sau mà các lớp khác nhau có thể ẩn. Tất cả các lớp thực hiện công việc grunt thực tế đều cần phải được đăng ký với Factory để nó biết lớp nào sẽ khởi tạo một tập các tham số.

Lưu ý: thay vì các giao diện, bạn cũng có thể sử dụng các lớp cơ sở trừu tượng, nhưng nhược điểm là đối với các ngôn ngữ kế thừa duy nhất, nó giới hạn bạn trong một lớp cơ sở duy nhất.

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');

Mã nằm trong cú pháp Delphi (Pascal) vì đó là ngôn ngữ mà tôi quen thuộc nhất.

Sau khi tất cả các lớp thực hiện được đăng ký với nhà máy, bạn sẽ có thể yêu cầu một tham chiếu giao diện đến một thể hiện của một lớp như vậy. Ví dụ:

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

sẽ trả về một tham chiếu IReader cho một thể hiện của TXMLReader; một tham chiếu IWriter cho một thể hiện của TPowerPointWriter và một tham chiếu IRepftimeation đến một thể hiện của THTMLTable.

Bây giờ tất cả các công cụ kết xuất cần làm, là gắn kết mọi thứ lại với nhau:

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;

Giao diện IReader sẽ cung cấp các phương thức để đọc dữ liệu cần thiết bởi những người triển khai IRepftimeation để xây dựng biểu diễn dữ liệu. Tương tự IRepftimeation nên cung cấp các phương thức mà người triển khai IWriter cần xuất biểu diễn dữ liệu sang định dạng tệp xuất được yêu cầu.

Giả sử dữ liệu trong các tệp của bạn là dạng bảng, IReader và các giao diện hỗ trợ của nó có thể trông giống như:

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;

Lặp lại trên một bảng sau đó sẽ là một vấn đề của

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;

Vì các biểu diễn có thể là hình ảnh, đồ thị và văn bản trong tự nhiên, IRepftimeation có thể có các phương thức tương tự như IReader để duyệt qua một bảng được xây dựng và nó sẽ có các phương thức để lấy hình ảnh và đồ thị, ví dụ như một luồng byte. Nó sẽ tùy thuộc vào những người triển khai IWriter để mã hóa các giá trị bảng và các byte hình ảnh / đồ thị theo yêu cầu của mục tiêu xuất khẩu.


1

Mặc dù tôi đồng ý rằng cần có thêm thông tin để suy nghĩ về một kiến ​​trúc, cách đơn giản nhất để tạo ra các loại đối tượng khác nhau hoạt động giống nhau (tức là tất cả chúng sẽ tạo ra một đầu ra) là sử dụng mẫu nhà máy. Thêm thông tin ở đây

Mẫu phương thức nhà máy là một mẫu thiết kế sáng tạo hướng đối tượng để thực hiện khái niệm về nhà máy và giải quyết vấn đề tạo đối tượng (sản phẩm) mà không chỉ định chính xác lớp đối tượng sẽ được tạo. Bản chất của mẫu này là "Xác định một giao diện để tạo một đối tượng, nhưng để các lớp thực hiện giao diện quyết định lớp nào sẽ khởi tạo. Phương thức Factory cho phép một lớp trì hoãn việc tạo tức thời cho các lớp con." Từ wikipedia


1
Tôi nghĩ nó liên quan nhiều hơn thế. Ví dụ, giao thức nào sẽ được sử dụng để giao tiếp dữ liệu dọc theo các đường trong sơ đồ? Có thể có một biểu diễn dữ liệu phổ biến trong công cụ Kết xuất / bố trí, hoặc công cụ đó chỉ là một nhà máy cho các phương thức hoàn toàn tùy chỉnh, một cho mỗi dòng trong sơ đồ?
Robert Harvey

Không chắc chắn nếu tôi nhận được điểm của bạn ở đây. Bởi vì Nếu cần sử dụng một giao thức để giao tiếp các dòng trong sơ đồ thì tôi nghĩ rằng tôi đang dựa vào một bộ dịch vụ để tạo xuất khẩu (trong trường hợp này bạn sẽ muốn xem một số mẫu soa / tích hợp). Ngay cả khi điều này là đúng, giải pháp vẫn linh hoạt và đủ mạnh để sử dụng nhà máy. Có lẽ điều bạn muốn làm là tạo một giao diện chuyển đổi có hai phương thức: một phương thức nhận dữ liệu XML và phương thức khác cho dữ liệu JSON. Đối tượng trả về cho cả hai sẽ là đối tượng được chuyển đổi. Bằng cách đó bạn có thể lắp ráp bất cứ thứ gì bạn muốn.
Orposeuser

thực sự có hai câu hỏi trong tiêu đề: về nội dung (gif, pdf, html) và về vận chuyển (tệp cục bộ, http-reply-item). Để mở rộng câu trả lời @Orposeuser (+1): Tôi sẽ tạo một luồng bằng cách sử dụng một nhà máy có thể dễ dàng bỏ qua và dễ dàng hiển thị cho phản hồi http.
k3b

0

Bạn có thể kết thúc với một cái gì đó như thế này.

Hai nhà máy được đặt xung quanh:

1 - để chuyển đổi loại đầu vào (Json / XML) thành một triển khai cụ thể về cách chuyển đổi dữ liệu này thành hình ảnh / đồ thị

2 - Một nhà máy thứ hai để quyết định cách kết xuất đầu ra thành một Tài liệu / Tài liệu PDF

Đa hình sử dụng giao diện chung cho tất cả dữ liệu được hiển thị. Vì vậy, một hình ảnh / bảng có thể được di chuyển xung quanh như một giao diện dễ dàng.

1 - Nhà máy để chuyển đổi dữ liệu JSON / XML thành một triển khai cụ thể:

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);
}

Nhà máy dưới đây cho phép bạn chuyển đổi Dữ liệu xml hoặc Dữ liệu Json thành loại cụ thể chính xác.

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");
        }
    }
}

Việc triển khai cụ thể thực hiện tất cả các công việc nặng nề là chuyển đổi dữ liệu sang loại có liên quan. Họ cũng chuyển đổi dữ liệu sang giao diện IConvertedData, được sử dụng cho đa hình.

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;
    }
}

Bạn có thể thêm các triển khai này khi cần thiết, khi mã của bạn mở rộng.

Giao diện IConvertedData cho phép bạn chuyển một loại duy nhất vào giai đoạn tiếp theo: LƯU Ý: Bạn có thể không quay lại các khoảng trống ở đây. Nó có thể bằng một byte [] cho hình ảnh hoặc tài liệu OpenXml cho WordDocument. Điều chỉnh khi cần thiết.

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

Đa hình:

Điều này được sử dụng để chuyển đổi dữ liệu sang loại đầu ra có liên quan. tức là kết xuất thành PDF cho dữ liệu hình ảnh, có thể là dữ liệu kết xuất hình ảnh khác nhau cho 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 - Nhà máy quyết định định dạng đầu ra:

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");
        }
    }
}

Mỗi triển khai cụ thể hiển thị một phương thức phổ biến che dấu cách xuất khẩu được đưa trở lại các triển khai 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();
    }
}

Một khách hàng mẫu cho tất cả điều này sẽ là:

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

Chúng tôi đã giải quyết một vấn đề tương tự ở đây: https://ergebnisse.undredus2011.de/?locale=en Ở đó chúng tôi chủ yếu có "bảng" và "biểu đồ" để được xuất theo các định dạng khác nhau: pdf, excel, web. Ý tưởng của chúng tôi là chỉ định từng đối tượng được hiển thị dưới dạng một lớp Java riêng với các giao diện để tạo và đọc các lớp đó. Trong trường hợp của bạn, sẽ có 2 triển khai cho mỗi đối tượng để tạo (xml, json) và 4 triển khai để kết xuất (đọc).

Ví dụ: Bạn sẽ cần một số lớp cho Bảng: Bảng lớp (xử lý cấu trúc bảng, xác thực và nội dung) Giao diện Tạo bảng (cung cấp dữ liệu bảng, ô, nhịp, nội dung) Giao diện ReadTable (getters cho tất cả dữ liệu)

Có lẽ bạn không cần các giao diện (hoặc chỉ một) nhưng tôi nghĩ rằng nó luôn cung cấp một sự tách rời tốt đặc biệt hữu ích trong việc thử nghiệm.


0

Tôi nghĩ những gì bạn đang tìm kiếm là mẫu Chiến lược . Bạn có nhiều lớp để xuất dữ liệu theo định dạng mong muốn và bạn chỉ cần chọn một lớp thích hợp khi chạy. Thêm một định dạng mới sẽ đơn giản như thêm một lớp khác thực hiện giao diện cần thiết. Tôi đã thực hiện điều này thường xuyên trong Java bằng Spring để duy trì bản đồ các trình chuyển đổi, được khóa theo loại định dạng.

Như những người khác đã đề cập, điều này thường được thực hiện bằng cách tất cả các lớp thực hiện cùng một giao diện (hoặc xuống từ cùng một lớp cơ sở) và chọn việc thực hiện thông qua một nhà máy.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.