Jak se vyhnout frustraci s Java eventy?

Zelenac

Re:Jak se vyhnout frustraci s Java eventy?
« Odpověď #30 kdy: 02. 02. 2016, 20:43:40 »

Řešením by byla třída, která bude obhospodařovat posluchače – bude je umět zaregistrovat a odregistrovat a bude umět všem registrovaným posluchačům poslat zprávu. Zároveň si ošetří konkurenční přístup. To je kód právě pro jednu třídu, není potřeba žádná vícenásobná dědičnost a ta třída se použije ve třídách, které potřebují posílat nějaké události registrovaným posluchačům. (Ano, v jiných jazycích by se to dalo řešit vícenásobnou dědičností místo kompozice, ale to by bylo porušení principu single responsibility.)

Jenže to budu muset do jediného objektu zakomponovat více parametrů, v případě že jich posílám víc. Můžeš mi říct, jak si takovuto skvělou věcí pomůžu a jak mi toto vylepší kód?


perceptron

Re:Jak se vyhnout frustraci s Java eventy?
« Odpověď #31 kdy: 02. 02. 2016, 20:51:00 »
jak vravi Filip Jirsak: staci pouzit CopyOnWriteArrayList. to je thread safe list. nemusite synchronized(). je to lepsie nez bordel so synchronized a collections.synchronizesList ktore su blbe

ad viacnasobna dedicnost: namiesto nej delegation

Kód: [Vybrat]
[tt]interface Observable {
  addObserver(o)
  removeObserver(o)
}

class DelegatingObservable implements Observable {
  Collection observers = new copyonwritearraylist();

  addObserver(o) {
    observers.add(o)
  }

  removeObserver(o) {
    observers.add(o)
  }

}

class Socket implements Observable {
   DelegatingObservable delegate = new DelegatingObservable();

   addObserver(o) {
      delegate.addObserver(o)
   }

   removeObserver(o) {
    delegate.add(o)
  }

 

}[/tt]

Ivan Nový

Re:Jak se vyhnout frustraci s Java eventy?
« Odpověď #32 kdy: 02. 02. 2016, 20:51:32 »
Zdravím,

 zajímalo by mně, jak by zdejší Java guru vyřešili tohle:

Dělám si client-server komunikační aplikaci, kterážto se později vyvine do P2P. To vyžaduje knihovnu, která obstarává naslouchání na portu (SocketServer) a dále obsluhu vzniklých Socketů (keepAlive, odesílání práv, příjem zpráv, rušení připojení, info o délce neaktivity socketů, atd.). Dále je třeba vytvořit další zaobalení těchto tříd a vytvořit třídu která v sobě sdružuje další funkcionality: typ odeslané zprávy (číže protokoly pro: chat, soubor, signalizace). A vzniknout další a další.

Je zřejmé, že takováto věc vyžaduje spoustu událostí, píše-li se správně objektově a to je prostě v Javě boží utrpení. Pořád dokolečka psát: listener kolekce, metody pro vyvolání událostí, foreache, interfacy. Obzvláště ty interfacy jsou velká lahůdka: co když třída má 20 událostí a já chci v jiné třídě reagovat pouze na 1? To musím buďto:

1. Napsat jednotný IListener interface kde budou všechny události k dané třídě. To vede k tomu, že pakliže v nějaké jiné třídě potřebuji jen události 2, stejně se mi jich tam bouchne dalších 18 které tam budou v souboru nevyužité strašit.
2. Napsat pro každou jednu událost jeden interface. No tak to tedy hodně štěstí při vývoji takovéto architektury, protože každý interface musí být v samostatném souboru, což je obrovská halda úkonů, která je k tomu nutná.

Prostě takové aplikace je plná událostí, nejde to elegantně řešit nijak jinak. Co s takovýmto hrozivým jazykem?

PS: Píšu to v Javě ze studijích důvodů, jinak bych to napsal hned v Qt.

Na architekturu té aplikace se díváte ze špatné strany, nejdříve je třeba zvolit typ architektury, z toho vám vyplynou požadavky na nějaké třídy zajišťující tuto abstraktní vrstvu, v této fázi žádné eventy neřešíte. Například "pipe and filter architecture", "enterprise process-centric" nebo vámi preferovanou "event-centric"

Pak vytvoříte výkonnou část eventů, tedy to co se má udělat, když daná událost nastane, a event je jen lepidlo, mezi těmito vrstvami, které jsou prakticky na sobě nezávislé.Výkonná část eventu by měl být objekt, který lze zkonstruovat třeba i v rámci skriptu, který importuje data do aplikace mimo UI, jen ze vstupních dat uložených v xml, nebo db. Rozhodně by výkonná část aplikace neměla být závislá na UI a nějak s ním viditelně provázaná.




Kit

Re:Jak se vyhnout frustraci s Java eventy?
« Odpověď #33 kdy: 02. 02. 2016, 21:00:23 »
Proč tu kolekci observers nemáš synchronized?

A jak ji mám mit synchronized? Vím že metody se dají dát jako synchronized, v tom případě se zamyká tuším celý objekt, ale atributy?

Stačí trochu zagooglit, ne?

Kód: [Vybrat]
private Collection<T> observers = Collections.synchronizedList(new ArrayList<>());
BTW: Trochu mi uniká, proč děláš kolekci observerů a ne jejich abonentů...

Zelenac

Re:Jak se vyhnout frustraci s Java eventy?
« Odpověď #34 kdy: 02. 02. 2016, 21:17:10 »
Rozhodně by výkonná část aplikace neměla být závislá na UI a nějak s ním viditelně provázaná.

Tak tomu nerozumím. Kde jste nabral dojem, že je má aplikace závislá na UI? Já právěže dělám UI úplně odlišené od zbytku. Já mám přece architekturu vybranou už od začátku - řízenou událostmi. A mám v tom celkem pořádek, až na to, že není v Javě snadné psát pořádně eventy.

Teda já čím dál víc zabrouzdávám do útrob, tím míň se divím, že je tak v oblibě C#. Tam bych totiž nic takového nemusel řešit, vážně ne. Eventy jsou přece tak důležitá věc v OOP. Ok, Java je pole neorané, beru.


perceptron

Re:Jak se vyhnout frustraci s Java eventy?
« Odpověď #35 kdy: 02. 02. 2016, 21:29:06 »
Citace
Tam bych totiž nic takového nemusel řešit, vážně ne. Eventy jsou přece tak důležitá věc v OOP. Ok, Java je pole neorané, beru.
vsak to sa ani v jave neriesi: hore ste mali 3 a viac prikladov ako sa to realne pouziva

dajte mi kus kodu v C# ja vam ho prepisem do javy :-)

ak vam chybaju delegaty tak to je preto ze az do java 8 neboli lambdy a java je konzervativna vzhladom k syntax sugar

Ivan Nový

Re:Jak se vyhnout frustraci s Java eventy?
« Odpověď #36 kdy: 02. 02. 2016, 21:31:50 »
Rozhodně by výkonná část aplikace neměla být závislá na UI a nějak s ním viditelně provázaná.

Tak tomu nerozumím. Kde jste nabral dojem, že je má aplikace závislá na UI? Já právěže dělám UI úplně odlišené od zbytku. Já mám přece architekturu vybranou už od začátku - řízenou událostmi. A mám v tom celkem pořádek, až na to, že není v Javě snadné psát pořádně eventy.

Teda já čím dál víc zabrouzdávám do útrob, tím míň se divím, že je tak v oblibě C#. Tam bych totiž nic takového nemusel řešit, vážně ne. Eventy jsou přece tak důležitá věc v OOP. Ok, Java je pole neorané, beru.

No UI by se mělo dělat až nakonec. Událost není kliknutí na tlačítko Objednat, ale nová objednávka. A abyste naprogramoval reakci na událost nová objednávka, k tomu žádné UI nepotřebujete. Systém by měl být funkční i bez UI, jen s přístupem do vstupních dat v souborech, nebo v db.

Pokud k UI doděláváte akce, které přímo pracují s DB (více méně skrytě, přes nějaké ad hoc objekty) a primární je UI, dostanete se do problémů v každém jazyce.

čumil

Re:Jak se vyhnout frustraci s Java eventy?
« Odpověď #37 kdy: 02. 02. 2016, 21:31:59 »
Nejsem Java guru, ale, pokud chceš odpověď jak na to, řeknu ti: nepoužívej Javu. Java má jednu ohromnou výhodu, běží všude a je plně zpětně kompatibilní. Dnešní programy v Javě poběží i za deset let na jakékoli super hyper funky procesorové architektuře která se zrovna rozhodne dobít svět. Na druhou stranu, chybné rozhodnutí před 15 lety ovlivňuje Javu doteď. Kuli bezpečnosti třeba nejde udělat override operátorů, nejsou pořádné jak ty říkáš eventy, a není toho asi mnohem víc, zas tak se ale o svět Javy nezajímám, takže nebudu víc kecat.

Re:Jak se vyhnout frustraci s Java eventy?
« Odpověď #38 kdy: 02. 02. 2016, 21:34:26 »
Nejsem Java guru, ale, pokud chceš odpověď jak na to, řeknu ti: nepoužívej Javu. Java má jednu ohromnou výhodu, běží všude a je plně zpětně kompatibilní. Dnešní programy v Javě poběží i za deset let na jakékoli super hyper funky procesorové architektuře která se zrovna rozhodne dobít svět. Na druhou stranu, chybné rozhodnutí před 15 lety ovlivňuje Javu doteď. Kuli bezpečnosti třeba nejde udělat override operátorů, nejsou pořádné jak ty říkáš eventy, a není toho asi mnohem víc, zas tak se ale o svět Javy nezajímám, takže nebudu víc kecat.

Moje rada je: nenecaht si radit od lidi, co tomu nerozumeji.

Sten

Re:Jak se vyhnout frustraci s Java eventy?
« Odpověď #39 kdy: 02. 02. 2016, 21:42:05 »
Ty „eventy” z Qt se správně nazývají signály a Java je samozřejmě taky umí ;)

Re:Jak se vyhnout frustraci s Java eventy?
« Odpověď #40 kdy: 02. 02. 2016, 21:43:20 »
Stačí trochu zagooglit, ne?

Kód: [Vybrat]
private Collection<T> observers = Collections.synchronizedList(new ArrayList<>());
BTW: Trochu mi uniká, proč děláš kolekci observerů a ne jejich abonentů...
Což je z implementací s bezpečným konkurenčním přístupem to nejhorší řešení. Protože se zamyká jakýkoli přístup k té kolekci, což není potřeba. Z té kolekce se asi bude mnohem častěji číst a jenom málokdy se do ní bude zapisovat. A je úplně zbytečné, aby na sebe jednotliví čtenáři čekali, klidně mohou číst paralelně, konkurenční přístup je potřeba hlídat jenom v okamžiku, kdy se do kolekce zapisuje, plus v případě událostí bude potřeba asi synchronizovat tak, aby čtení z kolekce ve workflow navazujícím na přidání posluchače vždy vracelo i toho nově přidaného posluchače – jinak by se mohly některé události ztrácet. Obvykle se to dělá ve stejném vláknu (i kvůli optimalizaci), ale bůhví, jaké s tím má Zelenáč plány. Ale ani tenhle požadavek nevyžaduje řadit veškeré přístupy ke kolekci za sebe.

Zelenac

Re:Jak se vyhnout frustraci s Java eventy?
« Odpověď #41 kdy: 02. 02. 2016, 21:46:31 »
vsak to sa ani v jave neriesi: hore ste mali 3 a viac prikladov ako sa to realne pouziva

A přesto, řekni mi třeba, proč k java.util.Observable neexistuje generická varianta, nebo varianta tvá s tím delegátem?

K čemu konkrétně je to java.util.Observable, vysvětli mi ten jeho význam. Pokud to budu dědit, zamezím si tím dědění z jinačí třídy. Není k tomu ani IObservable, aby se to implementovalo přes delgáta, jak ty říkáš.

Říkaš že přepíšeš do Javy. Ok tady máš variantu v Qt:

Kód: [Vybrat]
#include <QObject>

class Counter : public QObject
{
    Q_OBJECT

public:
    Counter() { m_value = 0; }

    int value() const { return m_value; }

public slots:
    void setValue(int value);

signals:
    void valueChanged(int newValue);

private:
    int m_value;
};

void Counter::setValue(int value)
{
    if (value != m_value) {
        m_value = value;
        emit valueChanged(value);
    }
}


// někde v main:

Counter a, b;
    [b]QObject::connect(&a, SIGNAL(valueChanged(int)), &b, SLOT(setValue(int)));[/b]

    a.setValue(12);     // a.value() == 12, b.value() == 12
    b.setValue(48);     // a.value() == 12, b.value() == 48

Re:Jak se vyhnout frustraci s Java eventy?
« Odpověď #42 kdy: 02. 02. 2016, 21:47:37 »
Jenže to budu muset do jediného objektu zakomponovat více parametrů, v případě že jich posílám víc. Můžeš mi říct, jak si takovuto skvělou věcí pomůžu a jak mi toto vylepší kód?
Jakých víc parametrů, koho posíláte víc? Chcete z jednoho objektu posílat různé typy událostí? No tak si prostě implementujte třídu s metodami zaregistrujPosluchace(TypUdalosti, Posluchac), odregistrujPosluchace(typUdalosti, Posluchac) a posliUdalost(TypUdalosti, Data), implementaci téhle třídy si vložte do každé třídy, která má umět posílat události, a delegujte na tu třídu volání metod zaregistrujPosluchace a odregistrujPosluchace. A ty dvě metody si dejte do interface, který označí všechny třídy, které umí posílat události.

Sten

Re:Jak se vyhnout frustraci s Java eventy?
« Odpověď #43 kdy: 02. 02. 2016, 21:51:33 »
A přesto, řekni mi třeba, proč k java.util.Observable neexistuje generická varianta, nebo varianta tvá s tím delegátem?

K čemu konkrétně je to java.util.Observable, vysvětli mi ten jeho význam. Pokud to budu dědit, zamezím si tím dědění z jinačí třídy. Není k tomu ani IObservable, aby se to implementovalo přes delgáta, jak ty říkáš.

Observable je socket, ne ta třída, ve které ten socket je.

Sten

Re:Jak se vyhnout frustraci s Java eventy?
« Odpověď #44 kdy: 02. 02. 2016, 21:54:37 »
A přesto, řekni mi třeba, proč k java.util.Observable neexistuje generická varianta, nebo varianta tvá s tím delegátem?

K čemu konkrétně je to java.util.Observable, vysvětli mi ten jeho význam. Pokud to budu dědit, zamezím si tím dědění z jinačí třídy. Není k tomu ani IObservable, aby se to implementovalo přes delgáta, jak ty říkáš.

Observable je socket, ne ta třída, ve které ten socket je.

Pardon, v Qt terminologii se tomu říká signál. (Interně MOC taky vygeneruje instance pro každý signál, který si drží posluchače, tj. observery.)