Article View: pl.comp.objects
Article #14850Re: kolekcja/manager obiektów
From: Przemek Pokrywka
Date: Mon, 17 Jul 2006 19:06
Date: Mon, 17 Jul 2006 19:06
311 lines
18793 bytes
18793 bytes
Sektor van Skijlen napisał(a): > Dnia Thu, 13 Jul 2006 22:20:23 +0200, Przemek Pokrywka skrobie: > >>>>Czy nie byłoby lepiej, gdyby to użytkownik operował bezpośrednio na >>>>Session? Przedstawiony schemat, który często napotykam, pachnie mi >>>>antywzorcem Man-In-The-Middle. >>> >>>To zależy. W przypadku Javy pewnie tak (bo nie da się zabronić dostępu do >>>zewnętrznie zdefiniowanej klasy). W przypadku C++ nie jest to już takie >>>oczywiste, bo można zrobić klasę taką, do której metod (w tym konstruktora) ma >>>dostęp tylko inna (wskazana) klasa. W takim przypadku ktoś "z zewnątrz" mógłby >>>wszelkie operacje wykonać tylko za pośrednictwem managera. > >>W charakterze dygresji technicznej: w Javie też się tak da, umieszczając >>managera i Session w tym samym pakiecie (namespace) i deklarując >>wszystkie składowe klasy (w tym konstruktor) jako widzialne tylko w >>obrębie pakietu (tzw. widoczność domyślna). > > Śmiech na sali, też mi ochrona :). To nie przeczy wcale stwierdzeniu, > że w Javie nie da się zabronić dostępu do zewnętrznie zdefiniowanej klasy. > Dostęp w obrębie pakietu co najwyżej go tylko utrudnia, bo w tym celu muszę > sobie zdefiniować klasę w tym samym pakiecie, co nie jest przecież niemożliwe. > > Nawiasem mówiąc, podobna sprawa istnieje w Tcl - tam przestrzenie nazw > domyślnie są całkowicie prywatne i można tylko udostępnić do eksportu > określone symbole (tzn. robiąc namespace import * wciąga się nie wszystkie > nazwy, ale te, które zostały zdefiniowane jako namespace export). Ale nikt mi > nie zabroni w zupełnie innym miejscu użyć sobie tej samej przestrzeni nazw. Oczywiście, że nie, ale skoro już używasz takiej samej przestrzeni nazw jedynie w celu uzyskania dostępu do elementów o ograniczonej widoczności, to lepiej orientuj się w tym co robisz, bo wg powszechnie uznanej wśród programistór Javy konwencji autor nie gwarantuje Ci wtedy poprawnego działania Twojej aplikacji. Uważam, że przestrzeganie takiej konwencji, wspierane cechą języka jest w większości przypadków znacznie lepszym rozwiązaniem, niż wybór pomiędzy dwoma skrajnościami oferowany przez C++: swobodny dostęp niezależny od namespace albo friend, wymuszający na chronionej klasie posiadanie wiedzy o swoim kręgu przyjaciół. Swoją drogą, brak konstrukcji friend jeszcze nigdy mi jakoś w Javie nie przeszkodził i nie słyszałem też żeby komuś innemu (nie widziałem zgłoszonych w tej sprawie Java Specification Requests). >>ale w tym wypadku Session nie byłoby to sensowne (występuje >>jako parametr publicznej metody managera). > > A może właśnie niekoniecznie to tak powinno być! Może powinieneś operować > jakąś klasą bazową dla Session, która jest dostępna publicznie, ale samą klasą > Session może operować tylko manager? Tak, żeby ta klasa, która jest publiczna > dawała tylko możliwość identyfikowania sesji i pokazywania managerowi, o jaką > sesję chodzi - ale operacje na niej może już wykonać tylko manager? > >>>Można też stosować taką technikę, że to, co podajesz do metody managera (tu >>>podajesz Session), nie będzie bezpośrednim wskazaniem na obiekt, tylko jego >>>identyfikatorem. Czyli z zewnątrz można tylko menedżerowi powiedzieć, o jaki >>>obiekt nam chodzi, ale nie można na nim samodzielnie wykonywać żadnych >>>operacji. > >>Faktycznie można, ale nie ta ścieżka dyskusji jest dla mnie najbardziej >>interesująca, więc pozwolę ją sobie pominąć. > > Mięczak lol ;) Jednym słowem bardzo chesz o tym porozmawiać :-). Najchętniej uczyniłbym to w oddzielnym wątku (temat "opaque identifiers"), bo w tym jest już poruszona wystarczająca liczba problemów. Sądzę, że jak skrytykuję Twój pomysł, to będziesz go zaciekle bronił :-) Jeśli tak, to bardzo Cię proszę, w oddzielnym wątku. W skrócie moja niechęć do tego rozwiązania bierze się stąd, że kod kliencki w moim przekonaniu nie powinien być zmuszany do operowania większą liczbą obiektów, niż to konieczne. Jeśli _może_ operować Sesją (albo jednym z interfejsów Sesji, jeśli konieczne jest zabronienie klientom dostępu do określonych metod tej klasy), to po co kazać mu operować na IdentyfikatorzeSesji oraz na MenedżerzeSesji (zakładam, że mówimy o kliencie, który tę Sesję skądś już ma - nie musiał jej wyszukać w SessionMenedżerze)? Drugi powód to moja osobista preferencja - od czasu, gdy zacząłem programować obiektowo, przedkładam wyrażenia typu obiekt.operacja() nad algorytm(struktura_danych), a metoda deactivate(Session) klasy SessionManager przypomina mi to ostatnie wywołanie. Nie lubię zredukowanych obiektów typu "opaque identifier", Transfer Objects, albo rozpowszechnionych w świecie Javy tzw. "JavaBeans" - JavaBeans zredukowanych do roli struktur danych, bez ciekawego zachowania. Programować przy pomocy "opaque identifiers" można bez żadnych obiektów. >>Przyjmijmy >>jednak, że możliwość deaktywacji sesji z zewnątrz jest udostępniona na >>potrzeby administratora systemu, który lubi od czasu do czasu się >>powtrącać i coś skasować względnie zdeaktywować. > > > No to dobra - a teraz kolejne pytanie: co to jest deaktywacja sesji i jakie > konsekwencje ma ona dla całego systemu? Innymi słowy - tu już wtrącam znów z > teorią stanów cząstkowych - jakie operacje trzeba wykonać w celu deaktywacji > sesji, by pozostawić cały system w stanie stabilnym? > > Skąd pytanie: załóżmy (bo być może tak jest), że manager zarządza sesjami i > manager musi w jakiś sposób odnotować w swoich zasobach, że dana sesja została > zdezaktywowana, w związku z czym musi, np., usunąć ją z jakiegoś zbiornika, a > może ma jakieś własne dodatkowe dane opisujące sesję i coś w nich trzeba w > związku z tym zmienić. W związku z tym, operacja deaktywacji, jaka może być > zdefiniowana wyłącznie jako metoda Session, będzie wykonywać deaktywację tylko > z poziomu samej siebie, ale nie z poziomu managera. Ponieważ stan w managerze > musi być w związku z deaktywacją zsynchronizowany ze stanem sesji, więc > wykonanie operacji na samej sesji doprowadza system do niestabilnego stanu (bo > sesja zdechła, a manager sobie tego odpowiednio nie odnotował). Jest dokładnie tak, jak piszesz. Jednak Twój wniosek, że "deaktywacja sesji z zewnątrz powinna być w jakiś sposób uniemożliwiona i możliwa do wykonania tylko przez managera" uważam za błędny. Ta deaktywacja _może_ być zrealizowana tak, jak mówisz, ale _lepszym_ rozwiązaniem jest zdaniem użycie w miarę ogólnego schematu powiadomień (żeby nie użyć słowa "Observer") do zadbania o to, by menedżer miał aktualny stan. Dlaczego lepszym? Lepszym dlatego, że klient, który posiada referencję do Sesji nie potrzebuje referencji do jej menedżera, żeby ją zdeaktywować. Co więcej, jeśli tę Sesję dostał od innego obiektu, może nawet nie wiedzieć, że coś takiego, jak menedżer sesji istnieje! Drugim powodem jest ważna zasada programowania obiektowego - Singular Responsibility Principle. Menedżer skupia się na swoim podstawowym zadaniu - wyszukiwaniu sesji (oczywiście można teraz słusznie zakwestionować jego nazwę i to będzie krok w dobrym kierunku), Sesja skupia się na swoich zadaniach. W nieszczęsnych programach, w których zdarzało mi się widzieć dyskutowany antywzorzec, obiekt Menedżera dublował metody Sesji 1:1, nawet wtedy, gdy nie potrzebował aktualizować swojego stanu przy zmianie danej Sesji - bo niby dlaczego miał dublować je wybiórczo? Prowadziło to do absurdalnego wręcz rozrostu kodu różnej maści Menedżerów, które w swojej większej części grały po prostu rolę Man in The Middle. Co do wspomnianej "hierarchizacji", to widzę wartość w dzieleniu aplikacji na logiczne "poziomy" i konsekwentnym stosowaniu reguły, żeby kod z jednego poziomu operował na identycznym poziomie abstrakcji (np. żeby operowanie na Sesjach nie mieszało się z obsługą wyjątków typu FileNotFoundException). Jednak stosowanie hierarchii potrafi też wypaczać się w potworki w rodzaju opisanych Menedżerów, na co trzeba zwracać uwagę. > Zauważ, że hierarchia jest tutaj tak, czy siak, narzucona przez sam fakt, że > sesje mają swojego managera. Jeśli to ma być manager, który zarządza sesją, to > zarządza również wszelkimi przejawami ich działania: tworzy sesje, zamyka > sesje, więc nie widzę powodu, dla którego nie miałby również mieć wyłaczność > na zarządzanie obiektami sesji. Obiekt sesji może mieć publiczny interfejs, > który pozwalałby jej na różne operacje, ale które sa charakterystyczne dla > obiektów "aktywnych", natomiast nie takie, które kończą jej życie. > > Hierarchia taka powoduje, że naturalnym podejściem staje się dzielenie > operacji na poziomy, przy czym operacje na niższym poziomie wykonują te > obiekty stojące niżej w hierarchii, a te na wyższym poziomie - wyżej. Manager > zatem ma dostęp do tego, co robi sesja, i jest w stanie sam na tej sesji różne > rzeczy wykonać, natomiast operacje samej sesji mają dotyczyć stanu tylko i > wyłącznie jej. Inaczej mówiąc, sesja operuje tylko na swoim własnym stanie, a > manager operuje na własnym stanie oraz na stanie sesji. Taki model narzuca > sama hierarchia. > > Dlatego zupełnie naturalną rzeczą jest, że sesja ma swoją metodę od > dezaktywacji, która wykonuje określone czynności wyłącznie w ramach sesji, > a manager w celu zdezaktywowania określonej sesji, każe sesji się najpierw > zamknąć, a następnie usuwa sesję. Manager nie potrzebuje, żeby sesja go o > czymkolwiek powiadamiała - sam z założenia rządzi sesjami i każe sesjom tylko > wykonać określone czynności. Być może popularną i wydającą się naturalną (ze względu na prostotę implementacji dla programisty), ale, co jest od tego ważniejsze - gorszą z punktu widzenia programisty-klienta. A jak wiadomo to "klient nasz pan". Dlaczego gorszą, opisałem wyżej. > Natomiast to, co ty tutaj próbujesz zrobić, to postawić managera sesji jako > kontraktora, czy współpracownika sesji, bo w określonych sytuacjach sesja > staje się nadzorcą dla managera. Tak niestety jest, również w technologii > sygnałów i slotów, że obiekt nadajnika staje się nadzorcą (nadzorcą > specjalizowanym oczywiście, czyli nadzorcą tylko w pewnym, zawężonym obszarze > działań) dla obiektu odbiornika (co nie staje w sprzeczności z faktem, że > obiekty mogą być takimi relacjami związane w obie strony). Niestety?? To raczej dobrze! Po to odbiorca zdarzeń się rejestruje w nadajniku, żeby ten ostatni go poinformował o pewnych zdarzeniach. Taki układ jest najczytelniejszy: SessionManager troszczy się o aktualność swojego stanu, więc korzysta z tego, że Sesje rozgłaszają zmiany swoich stanów i przy pierwszej nadarzającej się okazji (najczęściej konstrukcja Sesji) prosi Sesję, żeby jemu też dała znać o swojej deaktywacji. Tak więc mimo, że aktualizacja stanu SessionManagera odbywa się poprzez Sesję, to dzieje się tak na wyraźne żądanie SessionManagera, zatem to on kontroluje sytuację, a nie na odwrót. Sesja sama nie przypisze sobie żadnego SessionManagera (poza tym żeby to zrobić, to musiałaby mieć do niego jakąś referencję - a ja nie zakładam nawet tego, że ona wie _cokolwiek_ na temat istnienia SessionManagerów). Manager, jeśli miałby nawet potrzebę _zablokowania_ niektórych zmian w Sesji, mógłby się zarejestrować na odbiór pewnego zdarzenia, ogłaszanego _przed_ wykonaniem pewnej akcji (patrz constrained properties w specyfikacji JavaBeans). > A jak będziesz tworzył nową sesję, to jak to zrobisz? Będziesz wołał > konstruktor Session podając jej managera, jako argument? A Sesja wywoła > manager.addSession( this )? Zapewne tworzenie Sesji będzie odbywać się w SessionManagerze. Zatem tuż po jej stworzeniu SessionManager zarejestruje się w tej Sesji jako obiekt zainteresowany jej zmianami newSession.addStateChangeObserver(this). Sesja nie będzie nic wywoływać na swoich obserwatorach dopóki nie zmieni się jej stan. Natomiast SessionManager, świadomy początkowego stanu Sesji, w chwili tworzenia jej instancji zaktualizuje swój stan addSession(newSession). > Takie postawienie sprawy jest o tyle bez sensu, że manager w takim wypadku > właściwie do niczego nie służy, poza tym, że zawiera listę sesji. Lista sesji to bardzo ograniczone ujęcie i było świadomym uproszczeniem na użytek przykładu - poza nią manager może zawierać listę sesji aktywnych, listę sesji rozpoczętych w ostatniej godzinie, tak jak baza danych zawiera indeksy dla danej tabeli w celu szybszego wyszukiwania rekordów. Tak więc - zawiera listę sesji, ale prywatną i udostępnia szereg metod służących do wyszukiwania sesji. Mam nadzieję, że teraz już widać, że taki manager do czegoś służy? Co do jego nazwy, to już wspominałem, że mogłaby być lepsza - obecną stosuję wyłącznie z powodów historycznych - taką widziałem w kilku projektach. > Taki projekt > jest całkowicie na bakier z hierarchizacją, która stanowi ważną część > programowania obiektowego. Programowania to być może tak, bo raczej nie obiektowego w szczególności. Na bakier może być poza tym jedynie z hierarchizacją w pewnym szczególnym, wąskim rozumieniu, bo jak wykazałem wyżej, kontrola pozostaje w gestii managera, jedynie w mniej bezpośredni sposób. Dla mnie zresztą mógłby być na bakier z hierarchizacją, tak jak z wieloma innymi *-zacjami, jeśli tylko ostateczna jakość API _z_punktu_widzenia_klienta_ będzie przez to lepsza. Zastosowanie się w tym przypadku do zasad tak pojmowanej "hierarchizacji" bardzo dobrze pasuje do słów Adama o tryumfie technikaliów nad rzeczywistością, bo bardziej liczą się jakieś tam szczegóły wewnętrznej architektury, niż faktyczna użyteczność dla klientów. > Zależności zarówno stanów, jak i zachowania są > tutaj poplątane, odmiennie niż w strukturze hierarchicznej. A tak - te zależności są odmienne i to bardzo, ale jeśli połapanie się w nich stanowi dla Ciebie problem, to już raczej wyłącznie Twoja sprawa. > Jest to najgorszy > możliwy sposób wykorzystywania wiedzy książkowej, bo nie dość, że łamie to > wszelkie ugruntowane standardy programowania obiektowego, jak "hierarchizacja"? :-) Pokaż mi, co to za ugruntowany standard programowania obiektowego i jakie inne "wszelkie" równie mocno ugruntowane standardy mój sposób łamie > to jeszcze stanowi > swoisty przerost formy nad treścią. Dlaczego? o proszę :-) > Dlatego, że jeśli przyjmiemy już coś takiego, że manager nie rządzi sesjami, > tylko sesje go powiadajamiają o określonych działaniach, to PO JAKI CHUJ JEST > NAM TEN MANAGER? Koledze nerwy już puszczają od takich herezji :-) Ale gwoli sprawiedliwości dodam, że część zbulwersowania ma prawo wynikać z nazwy "manager", która jest - do omawianego zakresu odpowiedzialności - nieadekwatna. > Zrób po prostu listę sesji jako pole statyczne klasy Session! A to Ci dopiero pomysł, nie ma co! Wprowadzajmy więcej statycznych elementów, co tam - garść singletonów tu i ówdzie, jeszcze jakaś statyczna lista i nasze programy będą tak się nadawać do wykorzystania jako samodzielne komponenty (vide mój inny post), jak mało kiedy. Wybacz, ale konstrukcje typu static już przerabiałem, a z niektórymi z nich przyszło mi żyć do tej pory. I wierz mi, nie jest to nic, z czego bym się nadzwyczaj cieszył każdego dnia. > Odpada ci pisanie dodatkowej klasy SessionManager, odpada ci też robienie > jakichś wymyślnych interfejsów Observera. Wymyślnych?? Człowieku, nad jakim oprogramowaniem Ty pracujesz - u mnie Observer to chleb powszedni! > Masz zatem dwie możliwości: albo robisz to na zasadzie, że sesja podlega > managerowi i manager wyłącznie wykonuje wszelkie operacje, które zmieniają > "liczebność sesji", No to u mnie tak podlega, przez wzorzec Observer > albo manager jest ci całkowicie zbędny. Taak... I dokładam jeszcze kilka singletonów, bo kocham konstrukcję static ;-) Nie rozważaliśmy do tej pory jeszcze jednego aspektu - wiele obserwatorów jednej Sesji. Jest dla mnie normalnym scenariuszem, że zmianami w sesji zainteresowanych jest w jednym momencie kilku obserwatorów naraz - każdy z nich interesujący się odrębnym aspektem tej samej Sesji. Rozwiązanie hierarchiczne wypada znacznie gorzej od wzorca Observer wg fundamentalnej zasady Open-Closed. W wypadku Observera zgodność z tą zasadą otrzymujemy na starcie, w rozwiązaniu "hierarchicznym" musimy kombinować. Reasumując, nic a nic nie przekonałeś mnie do rozwiązania "zhierarchizowanego" (którego nie przypisuję wcale Tobie, bo jest rozplenione jak chwast po większości oprogramowania obiektowego jakie znam - stąd mój post na tą grupę). Chętnie jednak dowiem się, jak jeszcze uzasadnisz wyższość bronionego przez Ciebie rozwiązania, bo jak na razie nie dowiedziałem się o niczym, o czym nie wiedziałbym wcześniej. PS. Moje uznanie dla ogromu pracy włożonego w http://www.intercon.pl/~sektor/cbx/
Technical Details
Message-ID:
<e9gn3c$2c9$1@news.onet.pl>Path:
mbox-mo1.pugleaf.net!news-archive.icm.edu.pl!newsfeed.gazeta.pl!news.onet.pl!not-for-mailReferences:
<e8u9d9$bf1$1@news.onet.pl> <e8ufia$c2q$1@kujawiak.man.lodz.pl> <e969ua$3mv$1@news.onet.pl> <e96jth$fli$1@kujawiak.man.lodz.pl>Show Full Headers
Complete Article Headers
Path: mbox-mo1.pugleaf.net!news-archive.icm.edu.pl!newsfeed.gazeta.pl!news.onet.pl!not-for-mail From: Przemek Pokrywka <adres@zastrzezony.com> Newsgroups: pl.comp.objects Subject: Re: kolekcja/manager obiektów Date: Mon, 17 Jul 2006 21:06:08 +0200 Organization: Onet.pl Lines: 311 Message-ID: <e9gn3c$2c9$1@news.onet.pl> References: <e8u9d9$bf1$1@news.onet.pl> <e8ufia$c2q$1@kujawiak.man.lodz.pl> <e969ua$3mv$1@news.onet.pl> <e96jth$fli$1@kujawiak.man.lodz.pl> NNTP-Posting-Host: 114.inet.polhost.pl Mime-Version: 1.0 X-Trace: news.onet.pl 1153163180 2441 80.48.120.114 (17 Jul 2006 19:06:20 GMT) X-Complaints-To: usenet@news.onet.pl NNTP-Posting-Date: Mon, 17 Jul 2006 19:06:20 +0000 (UTC) X-Sender: 5aB4pqMdeQG1O30L902dNmlAzoKeNKcS In-Reply-To: <e96jth$fli$1@kujawiak.man.lodz.pl> X-Accept-Language: pl, en-us, en User-Agent: Mozilla Thunderbird 1.0.2 (Windows/20050317) Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit