<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Reactive Extensions &#8211; Strona Szoguna</title>
	<atom:link href="https://szogun1987.pl/show/tag/reactive-extensions/feed/" rel="self" type="application/rss+xml" />
	<link>https://szogun1987.pl</link>
	<description>Jeszcze wstawię tutaj jakiś głęboki cytat</description>
	<lastBuildDate>Tue, 20 Nov 2018 22:10:53 +0000</lastBuildDate>
	<language>pl-PL</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.3.2</generator>
	<item>
		<title>Nasza droga do Reactive Extensions – cz. 3. – Meta</title>
		<link>https://szogun1987.pl/show/nasza-droga-do-reactive-extensions-cz-3-meta/297/</link>
					<comments>https://szogun1987.pl/show/nasza-droga-do-reactive-extensions-cz-3-meta/297/#comments</comments>
		
		<dc:creator><![CDATA[szogun1987]]></dc:creator>
		<pubDate>Wed, 07 Nov 2018 10:59:02 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[C Sharp]]></category>
		<category><![CDATA[Reactive Extensions]]></category>
		<guid isPermaLink="false">https://szogun1987.pl/?p=297</guid>

					<description><![CDATA[W drugiej części serii&#160;opisałem jak zastosowanie wzorca Event Bus rozwiązało część naszych problemów, ale wprowadziła inne. W trzeciej i ostatniej części serii opiszę jak biblioteka Reactive Extensions&#160; (RX) rozwiązała te problemy, oraz dlaczego postanowiliśmy pozostawić niektóre obszary kodu bez zmian. Obserwator i obserwowany Wzorzec projektowy obserwatora i obserwowanego nie jest zbyt często wykorzystywany w aplikacjach &#8230; <p class="link-more"><a href="https://szogun1987.pl/show/nasza-droga-do-reactive-extensions-cz-3-meta/297/" class="more-link">Czytaj dalej<span class="screen-reader-text"> Nasza droga do Reactive Extensions – cz. 3. – Meta</span></a></p>]]></description>
										<content:encoded><![CDATA[
<p>W <a href="https://szogun1987.pl/show/nasza-droga-do-reactive-extensions-cz-2-event-aggregator-na-ratunek/240/">drugiej części serii</a>&nbsp;opisałem jak zastosowanie wzorca Event Bus rozwiązało część naszych problemów, ale wprowadziła inne. W trzeciej i ostatniej części serii opiszę jak biblioteka Reactive Extensions&nbsp; (RX) rozwiązała te problemy, oraz dlaczego postanowiliśmy pozostawić niektóre obszary kodu bez zmian.</p>



<span id="more-297"></span>



<h2 class="wp-block-heading">Obserwator i obserwowany</h2>



<p>Wzorzec projektowy obserwatora i obserwowanego nie jest zbyt często wykorzystywany w aplikacjach .Net. Wiąże to się z faktem iż C# wspiera zdarzenia (events),&nbsp; które w większości przypadków są rozwiązaniem wystarczająco dobrym. Microsoft zauważył jednak, że istnieją bardziej rozbudowane scenariusze, takie jak nasze, w których nie zdają one egzaminu, dlatego dodał interfejsy IObserver&lt;T&gt; i IObservable&lt;T&gt;. Różnią się one od klasycznej definicji książkowej tego wzorca kilkoma szczegółami:</p>



<ul><li>Są generyczne (parametryzowane typem)&nbsp;</li><li>IObservable zawiera tylko metodę Subscribe akceptującą jako parametr obserwatora i zwracającą obiekt implementujący IDisposable, zamiast wywołania metody Unsubscribe należy wywołać metodę Dispose z wyniku metody Register</li><li>Obserwator posiada 3 metody&nbsp;OnNext, OnError i OnCompleted i jest bardziej skoncentrowany na obserwacji zmiany jednej wartości niż ogólnego stanu obserwowanego obiektu.</li></ul>



<h2 class="wp-block-heading">RX &#8211; Linq dla obserwatorów</h2>



<p>LINQ jest bardzo potężnym fragmentem standardowej biblioteki .Net opartym o 2 proste interfejsy IEnumerable i IEnumerator. Sprawił że operacje na kolekcjach stały się tak proste, że większość programistów .Net prędzej zmieni pracę niż zrezygnuje z ich używania. LINQ jest zbiorem metod rozszerzających i wzorcu dekoratora: większość metod jako parametr przyjmuje instancję IEnumerable i ewentualnie inne parametry mające wpływ na zachowanie metody. Wewnątrz tej metody jest tworzona i zwracana instancja klasy implementującej IEnumerable, która akceptuje&nbsp; parametry metody rozszerzającej jako parametry konstruktora. Metoda GetEnumerator tej klasy wywołuje metodę GetEnumerator oryginalnej kolekcji i przekazuje ją do konstruktora własnej klasy implementującej interfejs IEnumerator, wraz z parametrami swojego konstruktora. Dopiero ta klasa podczas wywoływania metody MoveNext analizuje parametry przekazane w konstruktorze i dokonuje decyzji czy wywoływać metodę MoveNext z oryginalnego Enumeratora, oraz jak przekształcić jej wynik, aby otrzymać docelową kolekcję.</p>



<p>Zarówno interfejs IEnumerable jak i IObservable opisują serię danych, pozwalają odczytywać kolejne elementy, oraz dostarczają informacji o tym czy seria zawiera więcej elementów. Podstawową różnicą jest fakt iż w przypadku IEnumerable to kod kliencki musi odczytywać kolejne elementy, a w przypadku IObservable to biblioteka wysyła kolejne elementy.</p>



<p>Na tym etapie utworzenie zestawu rozszerzeń do interfejsu IObservable wydaje się być dobrym pomysłem, tak właśnie powstała biblioteka Reactive Extensions. Pomysł okazał się tak dobry, że został zaadaptowany w większości języków programowania. Oprócz oryginalnej dokumentacji stworzonej przez Microsoft, powstała&nbsp;<a href="http://reactivex.io/">alternatywna wielo-platformowa dokumentacja</a> pozwalająca lepiej zrozumieć koncepcje. Po zapoznaniu się z nią postanowiliśmy wykorzystać bibliotekę do implementacji jednej z funkcjonalności. Zaskoczył nas fakt iż pomimo, że integracja z RX nie była uwzględniona w oryginalnej wycenie zadania, udało się je dostarczyć na czas.</p>



<h2 class="wp-block-heading">Dostarczanie wartości właściwości gdy zostaje podniesione zdarzenie</h2>



<p>Jak wspominałem w pierwszej części artykułu API, z którego korzystamy składa się w większości z par właściwość &#8211; zdarzenie. Kluczowe więc dla nas było żeby istniał sposób na&nbsp; dostarczenie wartości właściwości po podniesieniu zdarzenia. Na szczęście okazało się, że RX posiada odpowiednią metodę</p>



<pre class="prettyprint lang-cs">var sizeObservable =
    Observable
        .FromEventPattern(
            handler =&gt; someObject.SizeChanged += handler,
            handler =&gt; someObject.SizeChanged -= handler)
        .Select(o =&gt; someObject.Size);</pre>



<p>Ponieważ w większości przypadków nasz kod wymagał aby aktualna wartość właściwości natychmiastowo wyświetliła się na ekranie, stworzyliśmy własne rozszerzenie, które do powyższej metody dodawało dostarczenie tej wartości w momencie subskrypcji.</p>



<h2 class="wp-block-heading">Komunikacja między wątkami</h2>



<p>Ponieważ nasza aplikacja wykorzystuje wiele wątków, wsparcie przesyłania wiadomości pomiędzy wątkami była czymś czego oczekiwaliśmy. RX posiada metodę ObserveOn, która jako parametr przyjmuje obiekt typu Dispatcher. Niestety nie mogliśmy jej wykorzystać ponieważ inna biblioteka, którą wykorzystujemy, ukrywa ten obiekt pod własną abstrakcją. Na szczęście okazało się, że napisanie takiego rozszerzenia (Dispatch) własnoręcznie nie jest szczególnie trudne: 1 metoda rozszerzająca, 2 klasy mniej niż 100 linijek kodu.</p>



<h2 class="wp-block-heading">Obserwowanie wielu źródeł na raz</h2>



<p><br>Często to co użytkownik&nbsp;widzi na ekranie jest wyliczane na podstawie kilku wartości dostarczanych przez bibliotekę.  Kolejną fukcjonalnością jakiej oczekiwaliśmy od RX była możliwość łączenia wartości z różnych źródeł. Rozwiązaniem jest metoda CombineLatest przyjmująca jako parametr kilka obiektów IObservable i funkcję która jako parametry akceptuje ostatnie znane wartości dostarczone przez obiekty Observable, a jako wynik zwraca wartość dostarczoną do obserwatora.</p>



<pre class="prettyprint lang-cs">Observable
    .CombineLatest(
        firstObservable,
        secondObservable,
        thirdObservable,
        (firstValue, secondValue, thirdValue) =&gt; firstValue * secondValue * thirdValue);</pre>



<h2 class="wp-block-heading">Poprawa wydajności</h2>



<h3 class="wp-block-heading">Filtrowanie wartości</h3>



<p>Podobnie jak LINQ, RX posiada metodę Where, pozwalającą usunąć z sekwencji wartości nie spełniających określonych warunków, odciążając w ten sposób obserwatora. Dodam że inne implementacje RX nazywają tą metodę Filter.</p>



<h3 class="wp-block-heading">Usuwanie duplikatów</h3>



<p>RX posiada metodę Distinct, która gwarantuje, że obserwator otrzyma każdą wartość tylko raz.W naszej aplikacji jednak okazało się, że znacznie bardziej użyteczna jest metoda DistinctUntilChanged, która usuwa duplikaty następujące po sobie. Ustawienie CombineLatest, DistinctUntilChanged i Dispatch w odpowiedniej kolejności pozwoliło wyeliminować większość nadmiarowej komunikacji między wątkami.</p>



<h3 class="wp-block-heading">Debouncing</h3>



<p>RX zwiera metodę Debounce. Która ogranicza częstotliwość dostarczania kolejnych wiadomości. Jest ona użyteczna jeżeli nowe wartości mogą przychodzą tak często, że użytkownik nie jest w stanie ich konsumować, a utrata części komunikatów nie jest problemem. Dobrym przykładem może tu być czujnik poziomu płynu chłodniczego, w trakcie jazdy po wyboistej drodze, gdy znajdujemy się w okolicach krytycznie niskiego poziomu. W takim przypadku czujnik co chwila wysyła informację, że wszystko jest OK albo że należy dolać płynu, to sprawia, że kontrolka na desce cały czas by mrugała denerwując użytkownika. Po zastosowaniu metody Debounce kontrolka zapalałaby się na kilka &#8211; kilkanaście sekund i gasła.</p>



<h2 class="wp-block-heading">Testy jednostkowe</h2>



<p>W naszym projekcie cały czas staramy się podnosić poziom pokrycia kodu testami. Jeżeli to ułatwia pracę stosujemy biblioteki Moq i NSubstitute. Niestety obie te biblioteki domyślnie zwracają null dla właściwości typu IObservable, co zmusza nas do rozszerzenia kodu inicjującego test. Nie jest to jednak tak uciążliwe na jakie wygląda.</p>



<h2 class="wp-block-heading">Analiza problemów z produkcji</h2>



<p>Podobnie jak LINQ i metody asynchroniczne, generuje bardzo długie i nieczytelne stosy wywołań. Czasami zdarza się, że w całym stosie nie ma żadnej linijki kodu należącej do naszej aplikacji.</p>



<h2 class="wp-block-heading">Nie rezygnujemy z event-agregatora</h2>



<p>Event agregator ma miejsce w naszym projekcie i nie planujemy go usuwać. Istnieją zdarzenia o których informujemy przy pomocy obydwóch mechanizmów.</p>



<p>Nasza podróż przez różne rozwiązania, nauczyła nas, że jeżeli istnieją różne rozwiązania jednego problemu, to każde z nich ma swoje wady i zalety, i nie należy się kurczowo trzymać jednego rozwiązania.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://szogun1987.pl/show/nasza-droga-do-reactive-extensions-cz-3-meta/297/feed/</wfw:commentRss>
			<slash:comments>3</slash:comments>
		
		
			</item>
		<item>
		<title>Nasza droga do Reactive Extensions &#8211; cz. 2 &#8211; Event Aggregator na ratunek</title>
		<link>https://szogun1987.pl/show/nasza-droga-do-reactive-extensions-cz-2-event-aggregator-na-ratunek/240/</link>
					<comments>https://szogun1987.pl/show/nasza-droga-do-reactive-extensions-cz-2-event-aggregator-na-ratunek/240/#comments</comments>
		
		<dc:creator><![CDATA[szogun1987]]></dc:creator>
		<pubDate>Sun, 16 Sep 2018 08:38:11 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[C Sharp]]></category>
		<category><![CDATA[Reactive Extensions]]></category>
		<guid isPermaLink="false">https://szogun1987.pl/?p=240</guid>

					<description><![CDATA[W poprzednim wpisie opisałem problem z wyborem architektury aplikacji przed jakim stanął nasz zespół. W drugiej części opiszę jakie problemy udało się rozwiązać dzięki wzorcowi event aggregator, jakie pozostały nie rozwiązane, a jakie powstały w wyniku jego użycia.]]></description>
										<content:encoded><![CDATA[
<p>W <a href="https://szogun1987.pl/show/nasza-droga-do-reactive-extensions-cz-1-wstep/232/">poprzednim wpisie</a> opisałem problem z wyborem architektury aplikacji przed jakim stanął nasz zespół. W drugiej części opiszę jakie problemy udało się&nbsp;rozwiązać dzięki wzorcowi event aggregator, jakie pozostały nie rozwiązane, a jakie powstały w wyniku jego użycia.</p>



<span id="more-240"></span>



<p>Wzorzec <a href="https://martinfowler.com/eaaDev/EventAggregator.html">Event aggregator</a>, zwany czasami mediatorem albo event busem, dostarcza kanału komunikacji pomiędzy modułami aplikacji, ograniczając powiązania między nimi: moduł wysyłający wiadomość nie ma pojęcia kto na niego zareaguje, nie wiem nawet czy ktokolwiek to zrobi. Moduł oczekujący na wiadomość zazwyczaj nie musi znać nadawcy, interesuje go tylko treść wysłanej wiadomości.</p>



<p>Modułem naszej aplikacji, w którym ten wzorzec jest szczególnie użyteczny, jest obszar powiadomień.</p>



<figure class="wp-block-image"><img decoding="async" fetchpriority="high" width="1240" height="480" src="https://szogun1987.azureedge.net/wp-content/windows-desktop.png" alt="" class="wp-image-274"/></figure>



<p>W aplikacji istnieje tylko jedna instancja klasy odpowiadającej za ten obszar, klasa ta nasłuchuje na zdarzenia wysyłane przez wiele różnych klas. Bez tego wzorca wyświetlenie powiadomienia o przyjściu nowej wiadomości wymagałoby śledzenia dostępności samego serwisu wiadomości, zmian na liście rozmów oraz zmian na liście wiadomości w każdej rozmowie. Co gorsza każdy moduł, który chciałby reagować na przyjście nowej wiadomości musiałby powtórzyć znaczną część tego kodu. Dzięki event-aggregatorowi ta część kodu jest napisana raz, w klasie która wysyła wiadomość, natomiast klasy zainteresowane przyjściem nowej wiadomości wywołują tylko jedną linijkę:</p>



<pre class="prettyprint lang-cs">_messageAggregator.Register<IncomingMessageNotification>(MessageHandlingMethod);</pre>



<p>Drugim problemem jakim rozwiązał ten wzorzec, jest komunikacja między wątkami. Napisaliśmy jedną metodę rozszerzającą do event-aggregatora, która przenosi obsługę powiadomienia na główny wątek aplikacji:</p>



<pre class="prettyprint lang-cs">public static void RegisterOnDispatcher(
    this MessageAggregator self,
    DispatcherService dispatcherService,
    Action handler)
{
    self.Register(message =&gt; dispatcherService.Invoke(() =&gt;f handler(message)));
}</pre>



<p>Zrozumienie ciała metody wymaga chwili zastanowienia, jednak jej użycie jest proste:</p>



<pre class="prettyprint lang-cs">_messageAggregator.RegisterOndispatcher<IncomingMessageNotification>(MessageHandlingMethod);</pre>



<h2 class="wp-block-heading">Problemy z event-aggregatorem</h2>



<p>Wzorzec ten jest tak wygodny, że bardzo szybko zdominował znaczną część naszego kodu. W pewnym momencie zorientowaliśmy się jednak że powoduje on pewne problemy, a innych nie rozwiązuje.</p>



<p>Po pierwsze wiele klas wylicza swój stan początkowy na podstawie stanu serwisu, a na wiadomość zapisuje się żeby odświeżyć swój stan, co powoduje że każda z tych klas ma dwie zależności: serwis i event-aggregator.</p>



<p>Wysłanie wiadomości przez event-aggregatora wymaga napisania dodatkowej klasy, ponieważ programiści są z natury leniwi starają się pominąć ten krok gdy tylko jest to możliwe, nawet kosztem &#8222;wycieku abstrakcji&#8221;. Zdarzały się przypadki gdy mieliśmy serwis, który nasłuchiwał na zdarzenia z dwóch innych serwisów i wyliczał jakąś wartość, jednak nie wysyłał żadnego powiadomienia o zmianie tej wartości. Klasy które korzystały z tej klasy nasłuchiwały na zdarzenia z oryginalnych serwisów.</p>



<p>Nasza aplikacja pozwala na zmianę wielu ustawień &#8222;w locie&#8221;, czyli bez konieczności restartu aplikacji. W momencie zapisu ustawień &#8222;menadżer ustawień&#8221; wysyła wiadomość. Wiele klas jest na nią zarejestrowanych i wykonuje swoją logikę, nawet jeśli konkretne ustawienie nie uległo zmianie, aby ograniczyć ten efekt dodaliśmy do wiadomości dodatkową informację o tym, które wartości uległy zmianie, co jednak zmusza nas do dopisywania kilku dodatkowych linijek kodu za każdym razem gdy pojawia się nowe ustawienie.</p>



<p>W aplikacji pojawiły się problemy wydajnościowe związane z komunikacją między wątkami. Co prawda wywołanie metody Dispatcher.Invoke nie jest szczególnie ciężkie i nie należy się go bać, a już na pewno nie kosztem niepoprawnego działania programu, jednak wywoływanie jej kilkanaście tysięcy razy może przyprawić o zadyszkę nawet mocne komputery i spowodować &#8222;zawieszenie&#8221; się aplikacji. Wspomniana wcześniej metoda RegisterOnDispatcher powodowała, że &#8222;Handler&#8221; był uruchamiany na głównym wątku aplikacji, nawet w przypadkach gdy efektywnie nic nie robił np. pierwsza linijka obsługi zmiany ustawień zawierała sprawdzenie czy ustawienie, którego zmianą jest klasa jest zainteresowana, nie uległo zmianie. Trudniejszym do wyśledzenia przypadkiem był przypadek gdy ustawienie uległo zmianie, ale efektywna wartość wyliczona na jego podstawie pozostała bez zmian. W tej architekturze były to problemy bardzo trudne do naprawy.</p>



<p>W<a href="https://szogun1987.pl/show/nasza-droga-do-reactive-extensions-cz-3-meta/297/"> kolejnej części artykułu</a> opiszę jak biblioteka Reactive Extensions rozwiązała nasze problemy.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://szogun1987.pl/show/nasza-droga-do-reactive-extensions-cz-2-event-aggregator-na-ratunek/240/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Nasza droga do Reactive Extensions &#8211; cz. 1 &#8211; Wstęp</title>
		<link>https://szogun1987.pl/show/nasza-droga-do-reactive-extensions-cz-1-wstep/232/</link>
					<comments>https://szogun1987.pl/show/nasza-droga-do-reactive-extensions-cz-1-wstep/232/#comments</comments>
		
		<dc:creator><![CDATA[szogun1987]]></dc:creator>
		<pubDate>Thu, 06 Sep 2018 17:27:02 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[C Sharp]]></category>
		<category><![CDATA[Reactive Extensions]]></category>
		<guid isPermaLink="false">https://szogun1987.pl/?p=232</guid>

					<description><![CDATA[Jeden z produktów jakie ostatnio rozwijaliśmy w naszym zespole, jest aplikacją desktopową opartą o rozbudowaną bibliotekę, która dostarczała spójne API do komunikacji, opartej o różne protokoły związane z telekomunikacją, co sprawiało że generowała naprawdę dużo sygnałów. Chcesz wiedzieć jak sobie z tym poradziliśmy? ]]></description>
										<content:encoded><![CDATA[
<p class="has-background has-pale-cyan-blue-background-color">Artykuł w wersji anglojęzycznej jest dostępny na blogu firmy <a href="http://blog.grapeup.com/read/our-way-to-reactive-extensions-24">Grape Up</a></p>



<p>Jeden z produktów jakie ostatnio rozwijaliśmy w naszym zespole, jest aplikacją desktopową opartą o rozbudowaną bibliotekę, która dostarczała spójne API do komunikacji, opartej o różne protokoły związane z telekomunikacją, co sprawiało że generowała naprawdę dużo sygnałów.</p>



<span id="more-232"></span>



<h2 class="wp-block-heading">Architektura biblioteki</h2>



<p>Większość klas w tej bibliotece pasowała do takiego wzorca:</p>



<pre class="prettyprint lang-cs">public class Class1
{
    public void SetDescription(string description, CompletionHandler handler)
    {
         /* Some logic here */
    }

    public void SetSize(int size, CompletionHandler handler)
    {
        /* Some logic here */
    }

    public string Description { get; private set; }

    public int Size { get; private set; }

    public event EventHandler DescriptionChanged;

    public event EventHandler SizeChanged;
}
</pre>



<ul><li>Metody SetDescription i SetSize wysyłają wartość przekazaną jako pierwszy parametr i wywołują metodę przekazaną jako Handler gdy serwer potwierdzi albo odrzuci żądanie</li><li>Właściwości Description i Size zwracają ostatnią znaną wartość</li><li>Zdarzenia DescriptionChanged i SizeChanged są uruchamiane gdy serwer powiadomi aplikację o zmianie wartości &#8211; niezależnie czy zmiana była spowodowana przez wywołanie metody Set* czy przez inne interakcje z serwerem np. działanie drugiej aplikacji</li></ul>



<p>Biblioteka przetwarza wszystkie żądania na swojej własnej wewnętrznej puli wątków co ma swoje zalety i wady. Podstawową zaletą był fakt iż biblioteka, sama z siebie, nie wpływała na działanie wątku głównego aplikacji. Wadą był fakt iż wszystkie callbacki i zdarzenia podnoszone przez bibliotekę były uruchamiane na innym wątku, co wymuszało opracowanie jakiegoś mechanizmu do komunikacji między wątkami.</p>



<h2 class="wp-block-heading">Ręczne zarządzanie wątkami &#8211; Nie chcesz tego robić</h2>



<p>Już od początku rozwoju aplikacji zorientowaliśmy się, że ręczna komunikacja między wątkami kończy się powstaniem dużej ilości długiego i powtarzalnego kodu, który wygląda mniej więcej tak:</p>



<pre class="prettyprint lang-cs">public class SomeOtherClass : IDisposable
{
    private readonly SomeClass _someObject;
    private readonly DispatcherService _dispatcherService;

    public SomeOtherClass(
        SomeClass someObject,
        DispatcherService dispatcherService)
    {
        _someObject = someObject;
        _dispatcherService = dispatcherService;

        _someObject.DescriptionChanged += SomeObjectOnDescriptionChanged;
        _someObject.SizeChanged += SomeObjectOnSizeChanged;
    }
    
    private void SomeObjectOnDescriptionChanged(object sender, EventArgs e)
    {
        _dispatcherService.Invoke(LoadState);
    }

    private void SomeObjectOnSizeChanged(object sender, EventArgs e)
    {
        _dispatcherService.Invoke(LoadState);
    }

    private void LoadState()
    {
        PropertyVisibleOnUI = $"Description: {_someObject.Description} Size: {_someObject.Size}";
    }
    
    public string PropertyVisibleOnUI { get; set; }

    public void Dispose()
    {
        _someObject.DescriptionChanged -= SomeObjectOnDescriptionChanged;
        _someObject.SizeChanged -= SomeObjectOnSizeChanged;
    }
}</pre>



<p>Kod staje się jeszcze bardziej złożony jeżeli założymy, że niektóre właściwości klasy są złożonymi obiektami, które mają właściwości, zdarzenia, metody asynchroniczne. A takich warstw może być znacznie więcej.</p>



<p>API do obsługi wiadomości tekstowych napisane w tej konwencji mogło wyglądać tak:</p>



<pre class="prettyprint lang-cs">public interface IConversationService
{
    event EventHandler ConverstionStarted;
    event EventHandler ConversationEnded; 
    IEnumerable Conversations { get; }
}

public interface IConversation
{
    event EventHandler MessageAdded;
    void SendMessage(string body, CompletionHandler handler); 
    IEnumerable Messages { get; }
}

public interface IMessage
{
    event EventHandler IsReadChanged;
    bool IsMine { get; }
    string Body { get; }
    bool IsRead { get; }
}</pre>



<p>Koniecznie potrzebowaliśmy lepszego rozwiązania. W drugiej <a href="https://szogun1987.pl/show/nasza-droga-do-reactive-extensions-cz-2-event-aggregator-na-ratunek/240/">części artykułu</a> opiszę jak wzorzec event-aggregator pomógł nam pokonać te problemy.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://szogun1987.pl/show/nasza-droga-do-reactive-extensions-cz-1-wstep/232/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
	</channel>
</rss>
