Loose coupling - jak v javě rubrika: Programování: Java

3 jan.flos
položil/-a 23.5.2014

Pořád si říkám co je asi tak nejlepší, nejhezčí, nejpřehlednější způsob jak zajistit to aby byly objekty loose coupled, když chci reagovat
na události, které se v nich dějí. Podle způsobu Observer - Observable neboli Subscriber - Publisher

Vidím tyto možnosti

  1. Callback přez interface (odlehčená varianta Listeneru)
  2. Property change Listener
  3. Databinding
  4. Event Bus neboli Event Aggregator

Za nejpokročilejší považuji databinding. Event Aggregator vysílá eventy na sběrnici, v mnoha scénářích spíše střílení kanónem na vrabce.
Pokud někdo udělá metodu např addSelectionListener tak je jasný, že klient může dostávat tuhle message. U databindingu to tak zřejmé není.
Change listenery jsou pěkné, ale člověk se musí starat o jejich deregistrování. Používat weak references ?

V C# jsou eventy přímo programovým konstruktem.

Jak tedy manifestovat, že třída v Javě posílá eventy ?

odkaz
8 v6ak
odpověděl/-a 26.5.2014

Nejsympatičtější mi je mít nějaké Observables apod. a použít data binding, pokud se hodí. Pokud ne, mohu řešit ručně listenery. (Stejně data binding bude asi používat listenery uvnitř.)

Mimochodem, nějaké rozpojování (odregistrování listenerů) je nutné snad vždy. Ostatně všechny varianty používají nějaké callbacky (listenery), vždy si takto bude model držet reference zpět na svoje sledovatele a vždy sledovatel musí nějak říct, že už nepotřebuje sledovat novinky. Weak references na to nepoužívám, přijde mi to jako berlička. Snad leda jako fix velkého codebase, kde by bylo jiné řešení náročné. Na nových projektech bych se tomu radši vyhnul.

Spíš než weak references se zamyslím nad životním cyklem. Například při programování pro Android mám Activity, která začíná s onCreate a končí s onDestroy. V onCreate všechno nabinduju a v onDestroy zase odbinduju. Snad vždy půjde najít něco podobného.

Ručně by to samozřejmě byla docela otrava a hlavně by bylo velmi snadné na něco zapomenout. Mám na to třídu, která mi to řeší víceméně automaticky. Při vytvoření vazby zavolám např. binder.bind(assignable, observable) a ona si zaregistruje handler a zapamatuje si jej. V onDestroy pak zavolám něco jako binder.disconnect() a všechny handlery odregistruju.

Mám na to ještě pár triků, díky kterým nezapomenu například v onDestroy zavolat binder.disconnect(), ale to už je příliš specifické pro prostředí a jazyk. (Pomáhají mi Scalové traity nebo Scaloid.) Jo a úmyslně není až tak snadné udělat binding bez té třídy, která mi to spravuje, aby nebylo tak snadné omylem napsat memory leak.

Při implementaci jsem musel dávat trošku pozor ve složených Observables, aby registrovaly listenery až po zaregistrování prvního listenera a odregistrovávaly listenery po odregistrování posledního listenera, aby se vše kaskádovitě odregistrovalo. Opět je to situace, kdy mám objekt, který si registruje listenery, tak si je musí i správně odregistrovávat. Nejspíš jsem ale jen znovuvynalézal kolo (byť jsem rád, že vidím dovnitř) a nějaká knihovna typu RxJava nabídne něco velmi podobného.

Pro zobrazení všech 2 odpovědí se prosím přihlaste:

Rychlé přihlášení přes sociální sítě:

Nebo se přihlaste jménem a heslem:

Zadejte prosím svou e-mailovou adresu.
Zadejte své heslo.