Použít návrhový vzor? Jaký?   zodpovězená otázka

C#, Architektura, Optimalizace

Nacházím se v bodě, kdy potřebuji udělat opravdu správný objektový návrh. Pro zjednodušení mám tuto situaci:

Mám v objektu jedna textová data, která potřebuji uložit v různých formátech (výstup budou soubory s různou příponou), například (formáty jsou smyšlené, dat je v objektech více, ale princip stejný):

Text: "Máma mele maso."

1. formát : "1. <Máma mele maso>

2. formát : "(Máma mele maso)

3. formát : "'Máma mele maso'"

Celá opera se tedy liší jen ve výstupu, který potřebuji uložit a následně načítat.

Moje dosavadní návrhy:

1) udělat interface formát s běžným textem a potom udělat pro konkrétní formáty třídy, které by ho implementovaly a zároveň by musely každá overridovat třeba ToString, kde by byl výstup lišící se formátem

2) udělat jen jednu třídu pro všechny formáty a do ní dát například výčtový typ s formátem (dal by se za běhu měnit) a potom mít nějaký samostatný objekt, který by řešil ukládání a formát by přečetl z toho výčtu.

3) řešit to například pomocí Factory Method, jejíž potomci by implementovaly jednotlivý kód podle jejich formátu.

Cílem je, aby šly další formáty později nějak rozumně (pohodlně) přidávat, nebo ubírat. Ideálně pomocí návrhového vzoru, které se už nějakou dobu snažím dostat do hlavy.

Předem děkuji za návrhy

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Tak to je Builder - http://en.wikipedia.org/wiki/Builder_pat...

Návod, jak dojít k myšlence je snadný:

1) Potřebuješ konstruovat různé objekty, tedy nějaký tvořivý vzor.

2) Singleton, Prototype to neudělají, Abstract factory je na to moc drsná, obyčejná Factory method se dá použít, ale Builder, ten přesně popisuje tvůj problém.

Řešení:

Procházíš svoje textová data a voláš postupně metody definované abstraktním builderem, za nímž se skrývá uživatelem definovaný konkrétní builder, který tyto abstratkní metody implementuje. Některé z nich můžeš implementovat tak, že nebudou dělat nic, záleží na builderu. Některý na začátku přidá nějaké znaky, jiný zase ne.

Podle vzoru nemusíš ani definovat společného předka nebo interface pro výsledný produkt, protože každý konkrétní builder přresně ví, jaký produkt bude jeho výsledkem. Myslím, že diagram na wiki mluví sám za sebe.

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Není mi moc jasné, k čemu by se builder použil při formátování textu (v této konkrétní situaci). Máte nějaký jednoduchý příklad, kdy při této situaci lze smysluplně využít?

Obecně chcete builder používat v situacích, kdy je potřeba předávat "sadu příkazů", které postupně dávají dohromady výsledek. Například sestavování objektu při deserializaci (jeden příklad za všechny - implementace ProtoBuffers protokolu v Javě). Pokud je vstupem "jeden text", nedovedu si představit, proč jej používat.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Jasně. Formátování textu. Vstupem je libovolný text v normální textové reprezentaci a na výstupu může být html, xml, a další. Builder definuje metody jako AppendLine, StartListing, a spoustu dalších, které jednotlivé buildery mohou nebo nemusí implementovat.

Pak parsuju text a volám metody builderu, který mi sestaví výsledky dokument.

Tazatel chtěl vzor, dal jsem mu vzor. To, že hned nenapsal, že se jedná o tak snadný problém, jako je formátování titulků, je jiná řeč. Použití vzorů bych mu také vymluvil, kdybych to věděl.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Neznám detaily o tom, čeho chcete dosáhnout. Nicméně nejjednodušší se mi jeví:

- mít interface, kterému se předá objekt reprezentující vstup a ten vypíše výstup

- pokud je výstup vždy textový, předávat této třídě třeba TextWriter

Příklad:

interface ITextFormatter
{
  void Format(string input, TextWriter output);
}
class RawTextFormatter : ITextFormatter
{
  public void Format(string input, TextWriter output)
  {
    output.Write(input);
  }
}
...

Další typy formáterů by určovali, jak formátovat text. Určitě je možné to kombinovat a rozšiřovat. Například přidat jméno (pokud třeba chcete aby bylo možné si zobrazit seznam formáterů v UI), informace, zda zapisovat konce řádků atp. Stejně tak třeba nějaký globální seznam dostupných formatterů.

Nehledal bych v tom nic složitého.

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Děkuji za návrhy. Konkrétně se jedná o různé formáty titulků, čili každý titulek má:

- text

- čas, kdy se zobrazí

- některé formáty i číselné pořadí titulku

Problém je s časem, který se třeba ve formátu .sub zapisuje úplně jinak, než v .srt. Proto nevím, jestli vytvářet spíš třídy pro jednotlivé formáty, nebo by bylo vhodnější, jak vy říkáte, té jedné obecné třídě akorát předávat formátory.

Jednotlivé typy formátů se totiž mohou lišit nakonec i vlastnostmi, například barevný text (který některé formáty podporují, některé ne), a proto by bylo asi lepší spíš vytvořit více tříd, které by pak obsahovaly i ostatní případné vlastnosti.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Přesně tak bych to udělal. Základem všeho bude rozhraní (popř. abstraktní třída), která bude mít vlastnosti a metody společné pro všechny formáty titulků (a že jich je požehnaně, minimálně 20).

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Pokud se jedná o titulky, udělal bych to ještě konkrétněji.

Mějte třídu reprezentující seznam titulků (víceméně to může v být pole nějakého objektu s časem, textem, barvou, pozicí atp.).

Pak mějte interface, kterému se místo jednoho řetězce předá celý tento objekt a on ho zapište.

A nechte na samotné třídě, aby řádky prošla a jeden po druhém zapsala. Protože to procházení bude dělat téměř každý formatter, použijte navíc bázovou třídu. Například:

interface ISubtitleFormatter
{
  void Format(IEnumerable<SubtitleItem> items, TextWriter output);
}
abstract class SubtitleFormatterBase : ISubtitleFormatter
{
  public virtual void Format(IEnumerable<SubtitleItem> items, TextWriter output)
  {
    foreach(var item in items)
      FormatLine(item, output);
  }

  protected abstract void FormatLine(SubtitleItem line, TextWriter output);
}

A už jen naimplementujete konkrétní potomky:

class SomeFormatSubtitleFormatter : SubtitleFormatterBase
{
  protected override void FormatLine(SubtitleItem line, TextWriter output)
  {
    // implementace
    output.Write(line.TimeFrom);
    output.Write(" --> ");
    output.WriteLine(line.TimeTo);
    output.WriteLine(line.Text);
  }
}

Poznámka: Bázovou třídu jsem zvolil z toho důvodu, že mohou například existovat titulky, které vyžadují navíc hlavičku souboru atp. Proto je lepší řešit zápis celého souboru jednou metodou která může takový případný problém vyřešit.

nahlásit spamnahlásit spam 2 / 2 odpovědětodpovědět

Ano, tohle se mi jeví nejlépe.

Velmi děkuji

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Řešení 1) je ideální. Zbytek jsou na takový problém nevhodné a příliš komplikované záležitosti.

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět
                       
Nadpis:
Antispam: Komu se občas házejí perly?
Příspěvek bude publikován pod identitou   anonym.
  • Administrátoři si vyhrazují právo komentáře upravovat či mazat bez udání důvodu.
    Mazány budou zejména komentáře obsahující vulgarity nebo porušující pravidla publikování.
  • Pokud nejste zaregistrováni, Vaše IP adresa bude zveřejněna. Pokud s tímto nesouhlasíte, příspěvek neodesílejte.

přihlásit pomocí externího účtu

přihlásit pomocí jména a hesla

Uživatel:
Heslo:

zapomenuté heslo

 

založit nový uživatelský účet

zaregistrujte se

 
zavřít

Nahlásit spam

Opravdu chcete tento příspěvek nahlásit pro porušování pravidel fóra?

Nahlásit Zrušit

Chyba

zavřít

feedback