Mam ten istniejący kod, w którym mają klasę i metodę inicjowania w tej klasie. Oczekuje się, że po utworzeniu obiektu klasy muszą one wywoływać na nim inicjalizację.
Powód, dla którego istnieje metoda inicjalizacji Obiekt jest tworzony wcześnie, aby mieć zasięg globalny, a następnie metoda inicjalizacji jest wywoływana później po załadowaniu biblioteki DLL, od której zależy.
Problem z inicjalizacją Klasa ma teraz ten inicjalizator bool, który należy sprawdzić w każdej metodzie przed kontynuowaniem i zwraca błąd, jeśli nie jest zainicjowany. Mówiąc najprościej, to duży ból.
Jedno możliwe rozwiązanie Zainicjuj w konstruktorze. Miej tylko wskaźnik do obiektu w zasięgu globalnym. Utwórz rzeczywisty obiekt po załadowaniu biblioteki dll.
Problem z powyższym rozwiązaniem Każdy, kto utworzy obiekt tej klasy, musi wiedzieć, że należy go utworzyć dopiero po załadowaniu biblioteki dll, w przeciwnym razie zakończy się niepowodzeniem.
Czy to jest dopuszczalne?
call_once
w C ++ 11 . Projekty, które nie są jeszcze w C ++ 11, powinny zbadać, w jaki sposób call_once jest zaimplementowane w C ++ 11 (skup się na tym, jaki problem rozwiązuje, a następnie jak), a następnie ponownie zaimplementuj go w (starym) smaku C ++. Potrzebuje wielowątkowej operacji podstawowej bezpiecznej synchronizacji, której stan musi zostać zainicjowany statycznie (o stałej wartości). Należy pamiętać, że kompilatory w wersjach wcześniejszych niż C ++ 11 mogą mieć inne osobliwości, które należy spełnić.Odpowiedzi:
Brzmi jak praca dla wirtualnego proxy.
Możesz utworzyć wirtualny serwer proxy zawierający odniesienie do danego obiektu. Chociaż biblioteka DLL nie jest załadowana, serwer proxy może oferować pewne domyślne zachowanie klientom, po załadowaniu biblioteki DLL serwer proxy po prostu przekaże wszystkie żądania do rzeczywistego podmiotu.
Wirtualny serwer proxy będzie odpowiedzialny za sprawdzenie inicjalizacji biblioteki DLL i na tej podstawie zdecyduje, czy żądanie powinno zostać przekazane rzeczywistemu podmiotowi.
Wzór proxy w Wikipedii
Jak ci się podoba ten pomysł?
źródło
Nic użytecznego nie występuje, jeśli biblioteka DLL nie jest jeszcze załadowana; obiekt generuje tylko błąd. Czy to błąd krytyczny? Jak obsługiwany jest błąd?
Czy metodologia testowania gwarantuje, że ten błąd nigdy nie wystąpi w gotowym produkcie?
Brzmi jak zadanie do testowania, a nie do projektowania architektonicznego. Nie zwracaj tylko błędu,
assert
który nigdy się nie zdarza.Napraw wszystkich klientów klasy, którzy obecnie wychwytują i ignorują błąd, aby nie próbował powodować go w pierwszej kolejności.
Wzorem wielowątkowym może być ustawienie współużytkowanej zmiennej warunkowej po załadowaniu biblioteki DLL i spowodowanie, że konstruktor obiektu zaczeka (i zablokuje inne wątki), aż biblioteka zostanie załadowana.
źródło
Po pierwsze: unikaj globalnych obiektów jako szkodników, chyba że ich stan nigdy się nie zmienia (konfiguracja).
Teraz, jeśli utkniesz z tym, z jakichkolwiek powodów, istnieje kilka projektów, które prawdopodobnie mogą ci pomóc.
Wpadłem na dwa pomysły:
Użyj fasady, aby załadować bibliotekę DLL. Dostęp do obiektu można uzyskać tylko przez elewację, fasada ładuje bibliotekę DLL po utworzeniu i jednocześnie tworzy obiekt.
Użyj proxy, ale inteligentnego;)
Pozwólcie mi rozwinąć drugą kwestię, ponieważ obawiam się, że odpowiedź @edalorzo mogła cię przestraszyć:
Teraz masz tylko jeden czek.
Można to również zrobić za pomocą pewnego inteligentnego wskaźnika:
Tutaj rezerwujesz tylko miejsce na wskaźnik, początkowo zerowy, i dopiero po załadowaniu biblioteki DLL faktycznie przydzielisz obiekt. Wszystkie poprzednie dostępy powinny zgłaszać wyjątek (NullException: p?) Lub kończyć program (czysto).
źródło
To trudne pytanie. Uważam, że architektura może pomóc w rozwiązaniu tego problemu.
Z dowodów wynika, że .dll nie jest ładowany, gdy program jest ładowany. To prawie brzmi jak wtyczka.
Jedną z rzeczy, które przychodzą na myśl, jest konieczność zainicjowania pliku .dll. Programista musi założyć, że obiekt i tak nie wróci. Możesz być w stanie skorzystać z tego (
bool isObjectLoaded() { return isInitialized; }
), ale na pewno dostaniesz więcej raportów o błędach w porównaniu z czekami.Myślałem o singlu.
Jeśli wywołasz singletona, powinien zwrócić poprawny obiekt, jeśli może go odzyskać. Jeśli nie może zwrócić poprawnego obiektu, powinieneś otrzymać wartość błędu / nullptr / pusty obiekt podstawowy. To nie zadziałałoby, gdyby obiekt mógł na ciebie umrzeć.
Ponadto, jeśli potrzebujesz wielu instancji obiektu, możesz zamiast tego użyć czegoś takiego jak Fabryka.
źródło