Bezestavové OOP

anonym

Bezestavové OOP
« kdy: 30. 01. 2018, 14:48:32 »
Často jsem v situaci, kdy potřbuju napsat nějakou funkcionalitu. Řekněme, že budu chtít udělat funkcionalitu, která rozdělí 100GB XML na disku na menší XML.

Je jasné, že na toto udělám zvláštní třídu. Ale co už není jasné je, jestli ji udělat stavovou nebo bezestavovou. Např.:

Kód: [Vybrat]
Stavová třída by mohla vypadat takto:

class XMLSplitter {

public XMLSplitter(string inputXMLPath, int size) {}

public IEnumerator<string> getXMLPart() { yield return; }

}

Bezestavová třída takto:

class XMLSplitter {

public XMLSplitter() {}

public IEnumerator<string> getXMLPart(string inputXMLPath, int size) { yield return; }

}

Jenže to už bych mohl rovnou udělat statickou:

static class XMLSplitter {

public static IEnumerator<string> getXMLPart(string inputXMLPath, int size) { yield return; }

}


Stavová verze třídy má problém s tím, že se v ní bude muset resetovat stav při každém opuštění metody getXMLPart(). Navíc, stavovou verzi nelze použít ve více vláknech. Nestavová nebo statická verze tímto problémem netrpí, ale zase trpí tím, že si nemůžu definovat globální proměnné a do každé pomocné metody, kterou budu volat, budu muset propagovat parametry, které by mohly být součástí třídních atributů. To mi příjde, že vizuálně zhoršuje čitelnost kódu.

Tak jak s takovou situací naložit, nějaké návrhy?


anonym

Re:Bezestavové OOP
« Odpověď #1 kdy: 30. 01. 2018, 14:53:40 »
Kdybych měl odpovědět sám, udělal bych to tak, jak seto dělá v Java Spring. Tzn. všechny Servicy, tj. i můj XMLSplitter, by byly bezestavové. Jediné stavové třídy by byly ty, kterými se přenáší data mezi Service.

Např.



Kód: [Vybrat]

public XMLPart {

string originalFileName;
string content;
string size;

public void SaveToDisc(string location) {}

}

public XMLSplitter() {}

public IEnumerator<XMLPart> getXMLPart(string inputXMLPath, int size) { yield return; }

}

anonym

Re:Bezestavové OOP
« Odpověď #2 kdy: 30. 01. 2018, 15:15:30 »
Kurnik já když se nad tím teď tak zamýšlím, tak jsem asi skočil do pasti tomu yield return. Protože kdyby moje třída XMLSplitter prostince implementovala Iterator, tak by se o ni automaticky vědělo, že má stav vázaný na aktuální stav třídních atributů a tudíž že ji není možné jen tak recyklovat. Hmmm...

BoneFlute

  • *****
  • 1 981
    • Zobrazit profil
Re:Bezestavové OOP
« Odpověď #3 kdy: 30. 01. 2018, 15:18:50 »
Citace
že si nemůžu definovat globální proměnné a do každé pomocné metody, kterou budu volat, budu muset propagovat parametry
To není problém.

Citace
To mi příjde, že vizuálně zhoršuje čitelnost kódu.
To je otázka zvyku. Posuzovat kvalitu kódu podle počtu argumentů je špatná metrika.

Měl by si se ptát jinak:

- Má smysl, aby ta třída měla více reprezentací?
- Jde paralelizovat?
- Je nutné, aby si udržovala stav?

Obecně je lepší, když si objekt stav nepamatuje. Ano, je to poněkud ústup z původních ideí OOP, ale IMHO se to prostě neosvědčilo. Na druhou stranu jsou věci, které je nesmyslné, až nemožné dělat imutabilní. Například různé akumulátory, loggery, etc. Tedy objekty, jejichž smyslem je různě sbírat data, abych je na konci (nebo i klidně průběžně) zpracoval. Ne, že by to nešlo bez toho, ale někdy je to zbytečně kostrbaté.

Tvůj problém se splitováním velkého množství dat bych udělal jako stavovej, protože stejně potřebuju spolknout celej ten datovej blob, a nějak paralelizovat to stejně nejde.

Re:Bezestavové OOP
« Odpověď #4 kdy: 30. 01. 2018, 16:30:19 »
XML splitter bych taky udělal stavově, časem nejspíš přibudou další metody které budou operovat nad stejným xml.


Ivan Nový

Re:Bezestavové OOP
« Odpověď #5 kdy: 30. 01. 2018, 17:50:58 »
@BoneFlute

Ne, že by se to neosvědčilo, ale nebyla možnost něco paralelizovat a tudíž stavovost objektů nebyla na závadu.

UF

Re:Bezestavové OOP
« Odpověď #6 kdy: 30. 01. 2018, 17:52:55 »
trida zadnej stav nema a bezstavove OOP nato uz mi uplne dochazi fantazie - je neuveritelny co se da ze slov uvarit

Re:Bezestavové OOP
« Odpověď #7 kdy: 30. 01. 2018, 20:10:14 »
@BoneFlute

Ne, že by se to neosvědčilo, ale nebyla možnost něco paralelizovat a tudíž stavovost objektů nebyla na závadu.

Pokud není stav sdílený mezi vlákny tak stavovost objektů nikdy nevadila.

anonym

Re:Bezestavové OOP
« Odpověď #8 kdy: 30. 01. 2018, 20:23:27 »
No ono ta Java 8 zase takové terno není. Přibyly lambdy, streamy a Optional. Lambdy nejsou zase takové terno. Streamy... viděl jsem, jak to vypadalo, když Indové dostali jasně za úkolo používat streamy, protože je to asi velice profesionální. Vznikl z toho solidní nepřehledné běsy.

Optional taky nic moc, protože to má hrozně ukecanou syntax, viz:

Kód: [Vybrat]

// safe, ugly, omission-prone
if (project != null) {
    ApplicationType applicationType = project.getApplicationType();
    if (applicationType != null) {
        String typeDirName = applicationType.getTypeDirName();
        if (typeDirName != null) {
            System.out.println(typeDirName);
        }
    }
}

Kód: [Vybrat]

// let's assume you will get this from your model in the future; in the meantime...
Optional<Project> optionalProject = Optional.ofNullable(project);
// safe, java 8, but still ugly and omission-prone
if (optionalProject.isPresent()) {
    ApplicationType applicationType = optionalProject.get().getApplicationType();
    Optional<ApplicationType> optionalApplicationType = Optional.ofNullable(applicationType);
    if (optionalApplicationType.isPresent()) {
        String typeDirName = optionalApplicationType.get().getTypeDirName();
        Optional<String> optionalTypeDirName = Optional.ofNullable(typeDirName);
        if (optionalTypeDirName.isPresent()) {
            System.out.println(optionalTypeDirName);
        }
}

Kód: [Vybrat]

// safe, prettier
Optional<String> optionalTypeDirName = optionalProject
        .flatMap(project -> project.getApplicationTypeOptional())
        .flatMap(applicationType -> applicationType.getTypeDirNameOptional());
optionalTypeDirName.ifPresent(typeDirName -> System.out.println(typeDirName));


A ted to same C#:

Kód: [Vybrat]
var typeDirName = project?.ApplicationType?.TypeDirName;
if(typeDirName != null)
  System.Console.WriteLine(typeDirName);

Jinak, jestli někomu z Javistu připadá to použití Streamu jako pěknější a přehlednější, než původní klasické checkování na null, tak by si měl zajít k doktorovi nebo najít holku.

Kit

Re:Bezestavové OOP
« Odpověď #9 kdy: 30. 01. 2018, 20:32:49 »
Asi bych zvolil střední cestu, při které mohu dělit více XML současně:
Kód: [Vybrat]
class XMLSplitter {

    public XMLSplitter(string inputXMLPath) {
    }

    public IEnumerator<string> getXMLPart(int size) {
        // ...
        yield return;
    }

}

anonym

Re:Bezestavové OOP
« Odpověď #10 kdy: 30. 01. 2018, 20:46:54 »
A co tohle:

Kód: [Vybrat]
class XMLSplitter : IEnumerator<string> {
  XMLSplitter(string inputXMLPath, int size)
 
  string Current();
  bool MoveNext();
  void Reset();
}

Tím, že třída je IEnumerator je automaticky řečeno, že je stavová, takže s ní nikdo nebude špatně pracovat.

Kit

Re:Bezestavové OOP
« Odpověď #11 kdy: 30. 01. 2018, 21:09:27 »
...

Upřímně řečeno: Pracovat s XML jako se stringem je docela hloupost. Tohle je práce pro SAX.

anonym

Re:Bezestavové OOP
« Odpověď #12 kdy: 30. 01. 2018, 21:23:33 »
...

Upřímně řečeno: Pracovat s XML jako se stringem je docela hloupost. Tohle je práce pro SAX.

Proč? To vrací část toho XML jako String. To se pak může někam uložit. Co je na tom špatného?

Kit

Re:Bezestavové OOP
« Odpověď #13 kdy: 30. 01. 2018, 21:46:22 »
Upřímně řečeno: Pracovat s XML jako se stringem je docela hloupost. Tohle je práce pro SAX.

Proč? To vrací část toho XML jako String. To se pak může někam uložit. Co je na tom špatného?

Riskuješ tím nevalidnost výstupního XML. Nevalidních XML dostáváme hromadu jenom proto, že je někdo neumí generovat.

BoneFlute

  • *****
  • 1 981
    • Zobrazit profil
Re:Bezestavové OOP
« Odpověď #14 kdy: 30. 01. 2018, 21:53:13 »
@BoneFlute

Ne, že by se to neosvědčilo, ale nebyla možnost něco paralelizovat a tudíž stavovost objektů nebyla na závadu.

Paralelizovatelnost je nejčastěji skloňovaný důvod. Ale já v praxi spíše narážím na čitelnost a použitelnost. Immutable objekty jsou prostě víc blbuvzdorný. Je-li tam stav, je s tím hrozně práce.