🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: pl.comp.objects
Article #14849

Re: kolekcja/manager obiektów

#14849
From: Sektor van Skijlen
Date: Thu, 13 Jul 2006 23:10
262 lines
14776 bytes
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.

Z uwagi zapewne na tą iluzoryczną ochronę, w C++ zrezygnowano z jakiegokolwiek
sterowania dostępem wewnątrz przestrzeni nazw.

> Istnieje też w Javie 
> możliwość zadeklarowania całej klasy jako widzialnej jedynie w obrębie 
> pakietu,

Owszem, tak jest zresztą domyślnie.

> 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 ;)

> > Przykład z twojej strony nie ma za wiele sensu, bo problem nie polega na
> > sposobie zaimplementowania całego mechanizmu, lecz na logice całego "designu".
> > Rozstrząsanie, czy setDeactivated powinno być metodą managera, jest zupełnie
> > bezprzedmiotowe - zapytaj raczej, dlaczego ktoś z zewnątrz miałby mieć
> > możliwość deaktywacji sesji, po co mu to, a w związku z tym, czy sposób
> > operowania menedżerem, jaki opracowałeś, tworząc jego interfejs, przewiduje
> > deaktywację sesji z zewnątrz, czy nie.

> Dobre pytanie - być może najsensowniejszym rozwiązaniem byłoby to, gdyby 
> sesja sama się deaktywowała w określonych okolicznościach.

Do wykonania tego publiczność tej operacji nie jest potrzebna, to chyba
oczywiste.

> 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ł).

Jeśli tak jest, to w takim razie deaktywacja sesji z zewnątrz powinna być w
jakiś sposób uniemożliwiona i możliwa do wykonania tylko przez managera. A
manager wykona wtedy na danej sesji deaktywację, jako część operacji (po tej
operacji, a przed pozostałymi operacjami, następuje tzw. chwilowe zachwianie
stabilności stanu - jest to bardzo podobne np. do dodawania dwóch liczb
zespolonych: dodałeś już część rzeczywistą, a jeszcze nie dodałeś części
urojonej). A potem wykona odpowiednie aktualizacje w swoich danych w związku z
deaktywacją sesji.

> > Jeśli implementacja polega na przekierowaniu do metody sesji, to być może i
> > nie ma to za wiele sensu. Ale jeśli obiekt sesji dostaje poza tym kopa ze
> > zbiornika sesji, to już nie wydaje się być to takie bez sensu.

> a dla mnie nadal takie się wydaje, szczegóły niżej

Ciekawe ;)

> >>Wydaje mi się, że jeśli nawet taki manager chce koniecznie kontrolować 
> >>zmiany w swoich dzieciach, to lepszy do tego jest wzorzec Observer, 
> > 
> > Observer? Z choinki się urwałeś? 

> Observer, lecz kwestia mojego domniemanego urwania się z choinki jest 
> przedmiotem nieustannych sporów i kontrowersji, dlatego wolałbym, żeby 
> głos w tej sprawie zajął ktoś bardziej kompetentny od mojej skromnej osoby.

To będziesz musiał poszerzyć znacznie zakres poszukiwań poza tę grupę, bo tu
ci sukcesu na tym polu nie wróżę.

> > To jest zupełnie inny temat, inna kategoria.
> > Kto miałby być observerem kogo i - przede wszystkim - jakie stany cząstkowe
> > danego obiektu miałyby być "obserwowane" przez obserwatorów? Spróbuj
> > odpowiedzieć na powyższe pytanie, to będziesz wiedział, czy Observer się
> > nadaje. Hint:
> > 
> > http://sern.ucalgary.ca/courses/SENG/609.04/W98/lamsh/observerLib.html

> Obserwatorem miałby byc manager, obiektami obserwowanymi - Sessions. 
> Szczegóły niżej.

> Dla mnie najważniejsze we wzorcu Observer jest zdarzeniowość. Wcale nie 
> najważniejsza jest dla mnie synchronizacja jakiś stanów - dopuszczam 
> nawet Observera w przypadku obiektów bezstanowych.

Tak, zgadza się - chociaż wcale nie powiedziałem, że synchronizacja stanu
polega na tym, że obiekt A czyta jakiś stan cząstkowy obiektu B i na jego
podstawie zmienia jakiś stan cząstkowy u siebie. Zdarzenie wywołuję akcję, a
jej konsekwencje mogą mieć wielorakie znaczenie.

> Jeśli takie 
> pojmowanie tego wzorca utrudnia Ci analizę omawianego modelu, to możemy 
> umówić się, że chodzi mi o zdarzeniowość - jeden obiekt rejestruje się w 
> "nadajniku" zdarzeń jako odbiorca określonego typu zdarzeń - ten 
> odbiorca implementuje ustalony interface. Następnie "nadajnik" 
> powiadamia wszystkich zarejestrowanych odbiorców o interesujących ich 
> zdarzeniach, kiedy one wystąpią. Kod obsługi danego zdarzenia jest czymś 
> właściwym tylko dla odbiornika zdarzeń i nie musi ograniczać się do 
> aktualizowania swojego stanu.

Załóżmy.

> Jak widziałbym to w kodzie (pewne słowa kluczowe dodałem dla ich 
> większej czytelności dla osób nie programujących na codzień w Javie):

> public interface SessionObserver {
> // interface to inaczej klasa czysto abstrakcyjna w C++

>         public abstract void sessionDeactivated(Session deactivatedOne);

>         // inne metody powiadomień
> }

> public class Session {
>         List<SessionObserver> observers;

>         // metody do rejestrowania nowych obserwatorów

>         public void deactivate() {
>                 // zmiana swojego stanu
>                 for (SessionObserver observer: observers) {
>                         observer.sessionDeactivated(this);
>                 }
>         }
> }

> public class SessionManager implements SessionObserver {

>         // w którejś z metod tworzenia Session
>         // session.addObserver(this);

>         List<Session> activeSessions;

>         public void sessionDeactivated(Session deactivatedOne) {
>                 activeSessions.remove(deactivatedOne);
>         }
> }

> Tak to by wyglądało w dużym uproszczeniu. Mam nadzieję, że ten przykład, 
> choć niekompletny, wyjaśni w większym stopniu co miałem na myśli.

Taaa... pomarudził, że to "nie jest tylko taka synchronizacja stanu", po czym
pokazał przykład klasycznej synchronizacji stanu ;) lol

Ja wiedziałem od początku, co masz na myśli, i dlatego pokazanie przez ciebie
przykładu nie zmieniło mojego zdania, że jest to totalny bezsens.

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.

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).

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 )?

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. Taki projekt
jest całkowicie na bakier z hierarchizacją, która stanowi ważną część
programowania obiektowego. Zależności zarówno stanów, jak i zachowania są
tutaj poplątane, odmiennie niż w strukturze hierarchicznej. Jest to najgorszy
możliwy sposób wykorzystywania wiedzy książkowej, bo nie dość, że łamie to
wszelkie ugruntowane standardy programowania obiektowego, to jeszcze stanowi
swoisty przerost formy nad treścią. Dlaczego?

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? Zrób po prostu listę sesji jako pole statyczne klasy Session!
Odpada ci pisanie dodatkowej klasy SessionManager, odpada ci też robienie
jakichś wymyślnych interfejsów Observera. A jak potrzebujesz dostępu, to sobie
zapisz gdzieś referencję do tego pola i wszystko jest na miejscu.

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", albo manager jest ci całkowicie zbędny. Zastosowanie
Observera mniej więcej tak ci polepszy projekt, jak podświetlane podwozie w
samochodzie polepszy ci moc silnika.


-- 
//  _    ___         Michal "Sektor" Malecki <sektor(whirl)kis.p.lodz.pl>
\\ L_ |/ `|  /^\ ,()                         <ethouris(O)gmail.com>
// \_ |\  \/ \_/ /\ C++ bez cholesterolu: http://www.intercon.pl/~sektor/cbx
"I am allergic to Java because programming in Java reminds me casting spells"
Technical Details
Message-ID: <e96jth$fli$1@kujawiak.man.lodz.pl>
Path: mbox-mo1.pugleaf.net!news-archive.icm.edu.pl!news.gazeta.pl!newsfeed.pionier.net.pl!news.man.lodz.pl!not-for-mail
References: <e8u9d9$bf1$1@news.onet.pl> <e8ufia$c2q$1@kujawiak.man.lodz.pl> <e969ua$3mv$1@news.onet.pl>

Show Full Headers
Complete Article Headers
Path: mbox-mo1.pugleaf.net!news-archive.icm.edu.pl!news.gazeta.pl!newsfeed.pionier.net.pl!news.man.lodz.pl!not-for-mail
From: Sektor van Skijlen <ethouris@guess.if.gmail.com.is.valid.or.invalid>
Newsgroups: pl.comp.objects
Subject: Re: kolekcja/manager obiektów
Date: Thu, 13 Jul 2006 23:10:41 +0000 (UTC)
Organization: LODMAN - Metropolitan Area Network in LODZ, Poland
Lines: 262
Sender: Michal Malecki <sektor@zly.kis.p.lodz.pl>
Message-ID: <e96jth$fli$1@kujawiak.man.lodz.pl>
References: <e8u9d9$bf1$1@news.onet.pl> <e8ufia$c2q$1@kujawiak.man.lodz.pl> <e969ua$3mv$1@news.onet.pl>
NNTP-Posting-Host: zly.kis.p.lodz.pl
Mime-Version: 1.0
X-Trace: kujawiak.man.lodz.pl 1152832241 16050 212.191.89.2 (13 Jul 2006 23:10:41 GMT)
X-Complaints-To: abuse@man.lodz.pl
NNTP-Posting-Date: Thu, 13 Jul 2006 23:10:41 +0000 (UTC)
User-Agent: tin/1.6.2-20030910 ("Pabbay") (UNIX) (SunOS/5.9 (sun4u))
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit