Śledzenie wszystkich obiektów klasy

9

Jestem nowy w programowaniu obiektowym i ciągle napotyka ten problem. (Programuję w Javie) Byłem trochę niechętny, aby o to zapytać, ponieważ wydaje się to tak podstawowym problemem, ale nie mogę znaleźć tutaj żadnych informacji ani pytań na ten temat, a żadne z nich nie podręczniki, które przeczytałem (na dość podstawowym poziomie) dotknęły tej kwestii:

Często muszę śledzić wszystkie obiekty klasy, które zostały utworzone, aby iterować je w różnych celach. Ze względu na sposób, w jaki obecnie piszę programy, do wielu obiektów odwołuje się tylko inne obiekty, co oznacza, że ​​nie mam tablicy ani kolekcji, z którymi można by się do nich odwoływać.

Wyobrażam sobie, że skoro wydaje się to tak bardzo podstawową koniecznością w OOP, powinna istnieć dość zinstytucjonalizowana i prosta droga do tego? Czy zwykle stosuje się osobną listę wszystkich obiektów klasy?

Myślałem o statycznej tablicy lub kolekcji, do której poprzez konstruktor dodawany byłby każdy nowy obiekt. Nie działałoby to jednak z podklasami, ponieważ konstruktory nie są dziedziczone?

Zdaję sobie sprawę, że to pytanie może nie mieć jednej łatwej odpowiedzi; Mam tylko nadzieję, że ktoś może mnie trochę oświecić na ten temat. Mam wrażenie, że brakuje mi tutaj centralnej wiedzy.

zxz
źródło
5
Bardziej konkretny przykład śledzenia i trackera może pomóc. Ten problem jest obsługiwany na wiele różnych sposobów, w zależności od kontekstu, sposobu ich użycia itd.
JustinC
2
Myślę, że podchodzisz do problemu z niewłaściwego końca. Niezbyt często potrzebna jest lista wszystkich instancji danej klasy, a jej posiadanie powodowałoby różnego rodzaju problemy projektowe (ponieważ teraz nawet instancje tworzone w całkowicie niezwiązanych kontekstach zależą od siebie za pośrednictwem tej listy).
tdammers
1
„iteruj przez nie do różnych celów” ... takich jak ...? Ogólnie rzecz biorąc, obiekt ma jednego „właściciela” (nie jest to termin formalny, a jedynie stwierdzenie dotyczące semantyki programu) i nikt inny nie może mieć z nim „różnych celów”.
AakashM

Odpowiedzi:

8

Nie wiem, dlaczego musisz prowadzić listę wszystkich instancji klasy.

Spowodowałoby to wyciek pamięci, ponieważ obiekty te nigdy nie zostaną usunięte, ponieważ lista nadal będzie się do nich odwoływać, jeśli żadna inna klasa tego nie zrobi.

Ale jeśli naprawdę chcesz podążać tą trasą:

  1. Użyj wzoru fabrycznego. Klasa fabryczna z metodami, które inicjują klasę i zwracają obiekty. W ten sposób masz punkt centralny do kontrolowania instancji.
  2. Użyj wzorca Singleton do przechowywania listy lub list zawierających instancje.
  3. Spraw, aby fabryka umieściła każdy obiekt określonego typu na liście po ich utworzeniu.

Nawiasem mówiąc: konstruktory są dziedziczone.

Tulains Córdova
źródło
Można oczywiście nadać fabryce metodę „usuwania”, która usuwa instancję z listy śledzonych instancji. Ale nie ma możliwości jawnego wywołania tego. Lub podaj instancji metodę usuwania, która wyzwala metodę usuwania w swojej fabryce, która ma tę samą wadę, ale jest bardziej prawdopodobne, że zostanie wywołana, ponieważ jest bliżej użytkownika, bardziej widoczna.
jwenting
@jwenting Oczywiście, że tak. Ale to stworzyłoby brzydkie, niepotrzebne zależności między klasami a fabryką. Klasy nie powinny wiedzieć nic o fabryce, która je tworzy.
Tulains Córdova
stąd fabryka śledzi, co tworzy, a nie obiekt, który każe fabryce ją zarejestrować ...
jwenting
Singleton technicznie utrzymałby wszystkie instancje. Jedna pojedyncza instancja.
Rig
3

Należy zauważyć, że słabych referencji można używać w połączeniu z innymi podanymi rozwiązaniami, aby umożliwić śmieciarzowi usuwanie obiektów śledzonych, gdy nie są one już przywoływane gdzie indziej. Eliminuje to wycieki pamięci bez konieczności ręcznego usuwania obiektów w innym miejscu lub dbania o to, aby były śledzone. Możesz podać ReferenceQueue, aby otrzymywać powiadomienia o referencjach do uwolnionych obiektów.

Myślałem o statycznej tablicy lub kolekcji, do której poprzez konstruktor dodawany byłby każdy nowy obiekt. Nie działałoby to jednak z podklasami, ponieważ konstruktory nie są dziedziczone?

Konstruktory klas bazowych są wywoływane przed konstruktorami klas pochodnych. Każda klasa ma co najmniej jednego konstruktora i konstruktorów nie można zastąpić.

użytkownik2313838
źródło
2

Podczas tworzenia gier ludzie czasami chcą kolekcji „samozarządzającej” każdego typu obiektu gry.

Jedna implementacja wygląda następująco:

public class Car {

    static ArrayList<Car> list = new ArrayList<Car>();

    public Car() {
        list.add(this);
    }

    void kill() {
        list.remove(this);
    }

    static public void updateAll()
    {
        for (int i = list.size() - 1; i >= 0; i--)
        {
                list.get(i).update();
        }
    }

    public void update()
    {
        //update logic
    }
}

W ten sposób metody manipulujące kolekcją mogą być deklarowane jako statyczne, podczas gdy metody niestatyczne manipulują instancją (updateAll vs. update).

Choć jest to bardzo przydatne w przypadku bardzo prostych scenariuszy, przy nawet umiarkowanej złożoności zwykle najlepiej jest tworzyć osobne klasy menedżerów.

Kelly Thomas
źródło
1
Możesz bezpośrednio napisać static ArrayList<ListeStatic> list = new ArrayList<ListeStatic>();i pomiń statc {..}
cl-r
2
W języku Java nazwa metody zaczyna się od małej litery:uptdateAll(){..;}
cl-r
Ups ... minęło trochę czasu, odkąd publicznie wyemitowałem moją Javę
Kelly Thomas,
@ KellyThomas Samochód dodaje się do listy, usuwając się z niej. Brzmi nienaturalnie.
Tulains Córdova
1
@ CayetanoGonçalves jako pole statyczne to jedna lista wspólna dla wszystkich instancji.
Kelly Thomas
2

Spróbuj pomyśleć kontekst. Tworząc obiekt, robisz to w określonym kontekście. Na przykład, jeśli gra polega na strzelaniu do kosmitów, twoja aplikacja będzie cały czas tworzyć nowe obiekty kosmitów. Zostaną wyświetlone w polu o nazwie Space (która może być klasą reprezentującą główny interfejs użytkownika).

To zupełnie naturalne, że Space ma właściwość o nazwie currentAliens, która byłaby tablicą, do której dodajesz każdego nowo utworzonego kosmitę. Jeśli chcesz pozwolić swojemu użytkownikowi rozerwać tkaninę czasoprzestrzeni i zniszczyć wszystkich kosmitów na raz, przejdziesz przez tę kolekcję i zniszczysz każdy obiekt.

Jeśli chcesz mieć dostęp do tej kolekcji kosmitów z innych części aplikacji (np. Ze strony Ustawienia, na której możesz zezwolić użytkownikom na usunięcie niektórych rodzajów obcych za jednym zamachem), kontekst Ustawienia należy uzyskać dostęp do obiektu Space.

Wytze
źródło