Autor Wątek: Co zamiast zmiennych globalnych?  (Przeczytany 3909 razy)

Offline Shelim

  • Użytkownik
    • Homepage

# Styczeń 04, 2012, 22:08:00
Zastanawiam się czego używacie zamiast zmiennych globalnych dla obiektów które są... no, globalne w projekcie - np. managerów

Singleton odpada, bo nie chcemy chyba żeby taki manager dźwięków tworzył się w chwili odgrywania pierwszego dźwięku, prawda?

Zmienna globalna odpada, ze względu na brak wpływu na czas życia, brak określenia kolejności tworzenia i problem Androida: nie mamy pewności że aplikacja zostanie ubita przed ponownym uruchomieniem (czytaj. zmienne statyczne wcale nie muszą się zdestruktoryzować i skonstruktoryzować między uruchomieniami programu).

No to jak to rozwiązać w przypadku obiektów do których powinien być dostęp z każdego miejsca w kodzie? Czy może samo założenie "obiekt dostępny z każdego miejsca w kodzie" jest złe?

Offline Mr. Spam

  • Miłośnik przetworów mięsnych

Offline Estivo

  • Użytkownik
    • Blog

# Styczeń 04, 2012, 22:27:24
Nie wiem o co dokładnie ci chodzi bo przyznam się nie rozumiem dokładnie tego, ale jedyna odpowiedź jaka mi się nasuwa to - referencja?

Offline Shelim

  • Użytkownik
    • Homepage

# Styczeń 04, 2012, 22:31:24
To jest patent który odkryłem przy lekturze Thinking in C++
Foo & GetFoo()
{
   static Foo f;
   return f;
}
Bar & GetBar()
{
   static Bar b;
   return b;
}
W efekcie mamy globalny obiekt który zachowuje kolejność konstruowania nawet jeżeli obiekty są w różnych jednostkach translacji (jeżeli konstruktor Bar wymaga Foo, to skonstruuje go wywołując GetFoo() ). Niestety po pierwsze nadal nie mamy kontroli nad czasem życia obiektów, a po drugie statyczne zmienne są evil na Androidzie, jak już wspominałem :)

Offline Xirdus

  • Redaktor

# Styczeń 04, 2012, 22:37:16
Nie da się po prostu odpalać na tych staticach "= new Foo"? Przy uruchamianiu aplikacji wywołuj metodę inicjalizującą, która konstruuje obiekty globalne (destrukcja z założenia nie powinna być potrzebna).

Offline Avaj

  • Użytkownik

# Styczeń 04, 2012, 22:37:55
[oop-fanboy-mode-on]

Klasa manager sugeruje, że klasa zajmuje się managerowaniem czyli wszystkim i niczym, lepiej bardziej wyspecjalizować klasę. Poza tym, dlaczego potrzebujesz globalnego dostępu, i tak dźwięki będziesz odtwarzał z jednego miejsca w kodzie, a samo odpalenie dźwięku możesz zrobić innymi trikami np. jakimś callbackiem albo message loopem.

Offline raver

  • Użytkownik
    • Moja strona domowa.

# Styczeń 04, 2012, 22:38:15
Ogólnie staram się unikać zmiennych globalnych, ale czasami zmienna globalna to tak naprawdę najbardziej eleganckie rozwiązanie (szczególnie zmienna ograniczona do jednego pliku deklarowana jako static). Problem jest na tyle uzależniony od kontekstu, że po prostu trzeba myśleć co się robi i nie ma jednego słusznego sposobu.

Co do unikania singletonów/zmiennych globalnych to przychodzą mi 2 oczywiste pomysły:
1. Przekazywanie referencji do obiektów w konstruktorze - widać od razu co klasa "ma w środku", czego potrzebuje do życia. Nie jest taką czarną skrzynką która nie wiadomo co robi, jasno widać powiązania.
2. Przekazywanie referencji jako argument metody - bardzo często po prostu używa się niektórych zmiennych tylko w jakimś określonym zbiorze funkcji - czemu po prostu nie dodać tym wszystkim funkcjom nowego argumentu? Zalety identyczne jak w punkcie wyżej. Dobrym przykładem są np. funkcje render odpowiedzialne za rendering - można im wszystkim przekazywać wskaźnik do Renderera, bo przecież wiadomo że z niego korzystają (prawie zawsze).

Offline Shelim

  • Użytkownik
    • Homepage

# Styczeń 04, 2012, 22:45:06
@Raver
Patent z przekazywaniem zmiennych w argumencie wydaje się całkiem sensowny, zobaczmy czy pojawią się jeszcze jakieś ciekawe odpowiedzi :)

Edit: A, miałem się podpytać - jak w takim razie mają działać takie rzeczy jak Logger czy Config? Czy może mają być zagregowane do jakiejś jednej klasy typu Engine, która jest przekazywana jako parametr?

@Avaj
Okej, możliwe że źle zadałem pytanie - w jaki sposób mają działać assety czy renderer jeżeli nie za pomocą managerów?

Offline raver

  • Użytkownik
    • Moja strona domowa.

# Styczeń 04, 2012, 22:58:10
A, miałem się podpytać - jak w takim razie mają działać takie rzeczy jak Logger czy Config? Czy może mają być zagregowane do jakiejś jednej klasy typu Engine, która jest przekazywana jako parametr?

No singleton przesłania problem czasami - rozwiązuje 2 problemy:
1. Dostęp globalny.
2. Zapewnia że jest tylko 1 instancja obiektu na cały program.

W tym przypadku potrzebujemy tylko dostęp globalny, dlatego najlepsze jest najprostsze rozwiązanie:

Logger &GetUserLogger()
{
    static Logger logger("user-file.txt");
    return logger;
}

Logger &GetEngineLogger()
{
    static Logger logger("engine-file.txt");
    return logger;
}

Offline Liosan

  • Moderator

# Styczeń 04, 2012, 23:04:33
Singleton odpada, bo nie chcemy chyba żeby taki manager dźwięków tworzył się w chwili odgrywania pierwszego dźwięku, prawda?
Widzę dwa problemy w tym zdaniu:
- po pierwsze są inne rodzaje singletonów; można napisać taki, który jest inicjalizowany explicite na początku gry, i rzuca asercję przy próbie dostępu bez inicjalizacji. Do tego można dorzucić ręczne niszczenie - proste, kontrolowalne i testowalne.
- po drugie akurat menadżer dźwięku to chyba nie powinien być dostępny globalnie...? Menadżer zasobów pewnie tak, aktualna mapa pewnie tak, może renderer... ale menadżer dźwięków? Użyj eventów :)

Liosan

Offline Troll

  • Użytkownik
    • Oficjalna strona gry Gizarma

# Styczeń 04, 2012, 23:12:46
Ponieważ w appletach javy występuje podobny problem co w Androidzie (tak z opisu mi się wydaje) w Gizarmie globalne są w zasadzie tylko loggery. Jak sobie z tym poradzic? - najlepszym sposobem jest przekazywanie w konstruktorze parametrów / referencji do klas które są używane przez większośc metod tej klasy. Dzięki temu lista argumentów metod nie jest zabójcza.

Innym argumentem przeciwko zmiennym globalnym jest trudnośc w testowaniu. W momencie gdy masz 50 zmiennych globalnych wpływających na daną klase bardzo trudno jest pisac testy jednostkowe. Nigdy nie jesteś do końca pewien, czy odpowiednio ustawiłeś te wszystkie globale przed odpaleniem testu. Gdy wszystko jest ustawiane w konstruktorze i listach argumentów metod dokładnie wiesz z czego dana klasa korzysta.

Offline vashpan

  • Użytkownik
    • Strona

# Styczeń 04, 2012, 23:20:10
Dlaczego po prostu nie uzyjesz globalnych wskaznikow? Bedziesz sobie mogl je konstruowac i niszczyc kiedy tylko bedziesz mial ochote ;)

Ale nie siedze w Androidzie (narazie?) wiec nie wiem o co dokladnie tam chodzi, mogl byc dokladniej wytlumaczyc problem tam?

Akurat managery idealnie wrecz nadaja sie na globalne wskazniki... Dlaczego zakladac ze programista (albo wrecz "MY" ) bedziemy tak glupi ze zaczniemy przypisywac do tych managerow jakies inne wartosci niz tylko na poczatku programu w jakiejs metodzie 'init' ? Nazywamy je z jakims przedrostkiem 'g' i tyle. Co innego manager ktory jest inicjalizowany przewaznie tylko raz a co innego zmienne globalne ktora naprawde sa 'zmienne' ... te to rzeczywiscie moga znaczaco zmniejszyc czytelnosc kodu i jego bledoodpornosc.

Dlaczego 50 ? Na cala powazna nawet aplikacje nie bedzie wiecej niz kilkanascie managerow... Zmienne globalne to zwyczajny mechanizm jezyka i nie widze powodu dla ktorego mialbym z nich zrezygnowac.
« Ostatnia zmiana: Styczeń 04, 2012, 23:23:11 wysłana przez vashpan »

Offline Paweł

  • Użytkownik

# Styczeń 04, 2012, 23:25:10
Zazwyczaj klasy które mają mieć globalne instancje są na tyle rzadko tworzone / niszczone ( raz ) że używanie metod w stylu init/destroy nie jest większym problemem. Ułatwia to tym bardziej że i tak zazwyczaj biblioteki inicalizuje się zazwyczaj w mainie. Gdy się często tworzy takie obiekty można zrobić tak:
struct A{
  void init();
  void destroy();
};
template<class T>
struct Auto : public T{
  Auto() { init(); }
  ~Auto(){ destroy(); }
};
I można wybrać czy obiekt ma być konstruowany od razu, czy dopiero w mainie.

Offline Shusty

  • Użytkownik

# Styczeń 04, 2012, 23:30:17
@vashpan A przypadkiem aplikację na androida nie pisze się w Javie, w której nie ma wskaźników?


Offline owyn

  • Użytkownik

# Styczeń 04, 2012, 23:51:59
W Javie, poza typami prymitywnymi, są tylko wskaźniki. Nazywane są co prawda referencjami, ale bliżej im do wskaźników w C++ niż do referencji w C++.

Offline quaikohc

  • Użytkownik

# Styczeń 05, 2012, 00:03:04
W Javie, poza typami prymitywnymi, są tylko wskaźniki. Nazywane są co prawda referencjami, ale bliżej im do wskaźników w C++ niż do referencji w C++.

tak czy inaczej nie moga byc globalne (bez stworzenia klasy), i nie mozna ich niszczyc kiedy sie chce