Birden çok dışa aktarma türü için sağlam bir mimari mi tasarlıyorsunuz?


10

Tasarladığım yeni bir özellik için desenler veya mimari rehberlik arıyorum. Temel olarak, birden fazla dışa aktarma hedefi olan bir dışa aktarma özelliği ve yeni dışa aktarma hedeflerini takmanın çok fazla temel değişiklik gerektirmediği durumlarda onu yeterince genel hale getirmenin bir yolunu arıyorum. Dışa aktarma hedefleri ile, ister PDF, PowerPoint sunumları, Word belgeleri, RSS, vb olsun, farklı çıktı türleri söz ediyorum JSON ve XML temsil bir veri kümesi var. Bu veriler görüntüleri (herhangi bir sayı veya dışa aktarma türünü kullanarak [ör. PNG, JPG, GIF, vb.), Grafikleri, metinsel gösterimleri, tabloları ve daha fazlasını oluşturmak için kullanılır.

Ben daha fazla ihracat hedeflerinin eklenmesi işleme render ve düzen motoru bir tür içine tüm render ve düzeni soyut bir yol bulmaya çalışıyorum. Buna nasıl yaklaşılacağı konusunda herhangi bir yardım / öneri / kaynak çok takdir edilecektir. Şimdiden teşekkürler.

Ulaşmaya çalıştığım şeyin resimli bir temsili için.

resim açıklamasını buraya girin


Şimdiye kadar denediklerinizi tarif edebilir misiniz? Yerleşim motorunun gereksinimleri (sorumlulukları) nelerdir? Örneğin, sayfalama ve sayfa boyutu seçimini ele alması bekleniyor mu?
rwong

XML / JSON verileri aynı çıktı çalıştırmasında birden çok çıktı türü oluşturmak için kullanılabilir mi, yani XML verileriniz bir PDF belgesinde Resimler ve Tablolar ve Grafikler üretir mi? Veya XML / JSON verileri yalnızca PDF belgesi için bir Tablo veya Grafik oluşturmak için kullanılabilir mi?
Gibson

Bu tamamen xkcd.com/927 ile ilgili - tekerleği neden yeniden icat etmeye çalışıyorsunuz? DocBook, Markdown / pandoc vs. zaten var ...
Deer Hunter

Yanıtlar:


2

Benim için, gidilecek yol arayüzler ve bir fabrika olurdu. Arkasında çeşitli sınıfların gizlenebileceği arabirimlere referanslar döndürülür. Gerçek homurdanma işi yapan sınıfların hepsinin Fabrikaya kayıtlı olması gerekir, böylece bir dizi parametre verildiğinde hangi sınıfın örnekleneceğini bilir.

Not: arayüzler yerine soyut temel sınıfları da kullanabilirsiniz, ancak dezavantajı tek miras dilleri için sizi tek bir temel sınıfla sınırlandırmasıdır.

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 (Pascal) sözdiziminde kod olduğu için en tanıdığım dildir.

Tüm uygulayıcı sınıflar fabrikaya kaydedildikten sonra, böyle bir sınıfın örneğine bir arabirim referansı talep edebilmelisiniz. Örneğin:

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

bir TXMLReader örneğine bir IReader başvurusu döndürmelidir; TPowerPointWriter örneğine bir IWriter başvurusu ve THTMLTable örneğine IRepresentation başvurusu.

Şimdi tüm render motorunun yapması gereken her şeyi birbirine bağlamak:

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 arabirimi, verilerin temsilini oluşturmak için IRepresentation uygulayıcılarının ihtiyaç duyduğu verileri okumak için yöntemler sağlamalıdır. Benzer şekilde IRepresentation, IWriter uygulayıcılarının veri sunumunu istenen dışa aktarma dosya biçimine vermek için ihtiyaç duydukları yöntemleri sağlamalıdır.

Dosyalarınızdaki verilerin tablo halinde olduğunu varsayarsak, IReader ve destekleyici arayüzleri şöyle görünebilir:

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;

Bir masanın üzerinde tekrarlamak

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;

Temsiller görüntü, grafik ve metinsel nitelikte olabileceğinden, IRepresentation muhtemelen inşa edilmiş bir tablodan geçmek için IReader'a benzer yöntemlere sahip olacak ve örneğin bayt akışı gibi görüntü ve grafikleri elde etmek için yöntemlere sahip olacaktır. Dışa aktarma hedefinin gerektirdiği şekilde tablo değerlerini ve görüntü / grafik baytlarını kodlamak IWriter uygulayıcılarına bağlıdır.


1

Bir mimari hakkında düşünmek için daha fazla bilgiye ihtiyaç olduğunu kabul etsem de, aynı şekilde davranan (yani hepsi bir çıktı üretecek) farklı türde nesneler yaratmanın en basit yolu fabrika modelini kullanmaktır. Daha fazla bilgi burada

Fabrika yöntemi kalıbı, fabrikalar konseptini uygulamak için nesneye yönelik yaratıcı bir tasarım modelidir ve yaratılacak nesnenin tam sınıfını belirtmeden nesneler (ürünler) oluşturma sorunuyla ilgilenir. Bu örüntünün özü, "Nesne oluşturmak için bir arabirim tanımlamak, ancak arabirimi uygulayan sınıfların hangi sınıfı başlatacağına karar vermesine izin vermektir. Fabrika yöntemi, bir sınıfın alt sınıflara örnek oluşturmayı ertelemesine izin verir." Vikipedi sitesinden


1
Bence bundan biraz daha ilgili. Örneğin, verileri diyagramdaki çizgiler boyunca iletmek için hangi protokoller kullanılacak? Oluşturma / yerleşim motorunda ortak bir veri temsili olabilir mi yoksa bu motor, diyagramdaki her satır için bir tane olmak üzere tamamen özel yöntemler için sadece bir fabrika mıdır?
Robert Harvey

Emin değilim. Çünkü diyagramdaki satırları iletmek için bir protokol kullanmanız gerekiyorsa, o zaman ihracat oluşturmak için bir dizi hizmete güveniyorum (bu durumda bazı soa / entegrasyon kalıplarını görmek isteyeceksiniz) düşünüyorum. Bu doğru olsa bile, çözüm fabrikayı kullanacak kadar esnek ve sağlamdır. Belki de yapmak istediğiniz şey, iki yöntemi olan bir dönüştürücü arayüzü oluşturmaktır: biri XML verilerini alan diğeri JSON verileri için. Her ikisi için de dönüş nesnesi dönüştürülen nesne olacaktır. Bu şekilde istediğinizi bir araya getirebilirsiniz.
Orposuser

başlıkta aslında iki soru vardır: içerik (gif, pdf, html) ve taşıma hakkında (yerel dosya, http-response-item). @Orposuser (+1) yanıtını genişletmek için: Kolayca birim testine tabi tutulabilen ve http yanıtı için kolayca oluşturulabilen bir fabrika kullanarak bir akış oluştururdum.
k3b

0

Böyle bir şeyle sonuçlanabilirsin.

İki fabrika şu merkezlere dayanıyor:

1 - giriş türünü (Json / XML), bu verilerin bir görüntüye / grafiğe nasıl dönüştürüleceğine dair somut bir uygulamaya dönüştürmek için

2 - Çıktıyı bir kelimeye nasıl dönüştürdüğüne karar veren ikinci bir fabrika Belge / PDF Belgesi

Çok Biçimlilik, işlenen tüm veriler için ortak bir arabirim kullanır. Böylece bir görüntü / tablo kolay bir arayüz olarak hareket ettirilebilir.

1 - JSON / XML verilerini somut bir uygulamaya dönüştürecek fabrika:

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

Aşağıdaki Fabrika, xml Data veya Json Data'larını doğru beton tipine dönüştürmenize izin verir.

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

Somut uygulamalar, verileri ilgili türe dönüştürmek için tüm ağır işleri yapar. Ayrıca, verileri polimorfizm için kullanılan IConvertedData arabirimine dönüştürürler.

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

Kodunuz genişledikçe bu uygulamaları gerektiği gibi ekleyebilirsiniz.

IConvertedData arabirimi, bir sonraki aşamaya tek bir tür iletmenize izin verir: NOT: Buraya boşluk döndürmüyor olabilirsiniz. Resimler için bir bayt [] veya WordDocument için bir OpenXml belgesi olabilir. Gerektiği gibi ayarlayın.

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

Polimorfizm:

Bu, verileri ilgili çıktı türüne dönüştürmek için kullanılır. örneğin görüntü verileri için PDF'ye oluşturma, PowerPoint için farklı görüntü oluşturma verileri olabilir.

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 - Fabrika çıktı biçimine karar verecek:

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

Her somut uygulama, dışa aktarmanın IConvertedData uygulamalarına nasıl geri atıldığını maskeleyen ortak bir yöntem ortaya koyar

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

Tüm bunlar için örnek bir müşteri:

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

Burada benzer bir sorunu çözdük: https://ergebnisse.zensus2011.de/?locale=en Orada çoğunlukla farklı tablolarda dışa aktarılacak "tablolar" ve "grafikler" var: pdf, excel, web. Bizim düşüncemiz, bu sınıfları oluşturmak ve okumak için arabirimleri olan kendi Java sınıfı olarak oluşturulacak her nesneyi belirtmekti. Sizin durumunuzda her nesne için 2 uygulama (xml, json) ve renderleme (okuma) için 4 uygulama olacaktır.

Örnek: Tablolar için bazı sınıflara ihtiyacınız olacak: Sınıf Tablosu (tablo yapısını, doğrulamayı ve içeriğini işler) Arabirim CreateTable (tablo verilerini, hücreleri, açıklıkları, içeriği sağlar) Arabirim ReadTable (tüm veriler için alıcılar)

Muhtemelen arayüzlere (veya sadece bir tane) ihtiyacınız yoktur, ancak her zaman testte özellikle yararlı olan iyi bir ayrılma sağlar.


0

Bence aradığınız strateji stratejisi . Verileri istenen formatta çıkarmak için çeşitli sınıflarınız vardır ve çalışma zamanında uygun olanı seçmeniz yeterlidir. Yeni bir biçim eklemek, gerekli arabirimi uygulayan başka bir sınıf eklemek kadar basit olmalıdır. Bu genellikle Java'da Spring'i kullanarak, biçim türüyle anahtarlanan dönüştürücülerin haritasını korumak için yaptım.

Diğerlerinin de belirttiği gibi, bu genellikle tüm sınıfların aynı arabirimi uygulamasına (veya aynı temel sınıftan aşağı inmesine) ve uygulamayı bir fabrika aracılığıyla seçerek gerçekleştirilir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.