🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: pl.comp.objects
Article #14850

Re: kolekcja/manager obiektów

#14850
From: Przemek Pokrywka
Date: Mon, 17 Jul 2006 19:06
311 lines
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-mail
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>

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