2010-05-05 8 views
6

Większość programów, które piszę, to procesy o względnie płynnym przepływie, z określonym początkiem i oczekiwanym końcem. Same problemy mogą być skomplikowane, ale nie są łatwe do centralnego wykorzystania obiektów i programowania sterowanego zdarzeniami. Często po prostu ubieram się w różnorodne partie danych tekstowych, aby uzyskać różne dane tekstowe. Tylko od czasu do czasu muszę utworzyć klasę: Jako przykład, aby śledzić ostrzeżenia, błędy i komunikat debugowania, utworzyłem klasę (problemy) z jednym wystąpieniem (myErr), który uważam za przykład wzorca projektowego Singleton . Jako dodatkowy czynnik, moi koledzy są bardziej starzy (proceduralne) niż ja i nie znają programowania zorientowanego obiektowo, więc jestem niechętny tworzeniu rzeczy, których nie potrafią zinterpretować.Proszę opisać swoje zmagania z minimalizowaniem użycia zmiennych globalnych

A jednak wielokrotnie słyszę, że nawet wzorzec projektu Singleton jest rzeczywiście anty-wzorem i powinien być unikany, ponieważ zmienne globalne są złe.

Niewielkie funkcje wymagają podania kilku argumentów i nie wymagają znajomości konfiguracji (niezmiennej) lub stanu programu (zmiana) - zgadzam się. Jednak funkcje w środku łańcucha, które przede wszystkim kontrolują przepływ programu, wymagają dużej liczby zmiennych konfiguracyjnych i niektórych zmiennych stanu programu. Sądzę, że przekazanie kilkunastu argumentów do funkcji jest "rozwiązaniem", ale mało atrakcyjnym. Mógłbym oczywiście wciągnąć zmienne do jednej tablicy mieszania/dict/asocjacyjnej, ale to wygląda na oszukiwanie.

Na przykład, łącząc się z usługą Active Directory, aby utworzyć nowe konto, potrzebuję takich zmiennych konfiguracyjnych, jak nazwa użytkownika administracyjnego, hasło, docelowa jednostka organizacyjna, niektóre domyślne grupy, domena itp. Muszę przekazać te argumenty przez różne funkcje, które by ich nie używały, po prostu odsuwają je przez łańcuch, który ostatecznie doprowadziłby do funkcji, która faktycznie ich potrzebuje.

Chciałbym przynajmniej zadeklarować zmienne konfiguracyjne jako stałe, aby je chronić, ale mój wybrany język w dzisiejszych czasach (Python) nie zapewnia prostego sposobu, aby to zrobić, chociaż przepisy istnieją jako obejścia.

Liczne pytania dotyczące przepełnienia stosu wpłynęły na to, dlaczego? zła i wymaganego odskoku, ale nie często wspominajcie o tym, jak żyć z tym quasi-religijnym ograniczeniem. W jaki sposób rozwiązałeś, a przynajmniej rozwiązałeś kwestię zmiennych globalnych i stanu programu? Gdzie zawarłeś kompromis? Jakie były twoje sztuczki, oprócz przepychania się po stadach argumentów do funkcji?

+0

Dobre pytanie - czy kwalifikujesz zmienne na poziomie klasy (element) jako zmienne globalne? –

Odpowiedz

5

Myślę, że jest czas i miejsce na wzór singletonowy lub podobne sytuacje. Kluczową kwestią do zapamiętania jest to, że raz po raz wiele osób doświadczyło specyficznego przerażenia, jeśli chodzi o "niewłaściwy" wybór używania zmiennych globalnych/współdzielonych/statycznych, a także wzorca singleton.

W twoim przypadku mówisz konkretnie o konfiguracji. Nie widzę żadnej szkody w używaniu wzorca stylu singleton do dostępu do tych elementów konfiguracji. Każda aplikacja ma konfigurację, powinna znajdować się w miejscu, do którego można po prostu zadzwonić, nie ma potrzeby po prostu go przekazywać, co komplikuje więcej, niż pomaga.

Kluczem tutaj jest upewnienie się, że POTRZEBUJESZ potrzebnych informacji istnieje tylko raz, konfiguracja jest zdecydowanie jednym z najlepszych powodów, dla których znalazłem, aby używać tego typu wzorca.

3

Dane globalne, które są niezmiennymi lub dobrze zdefiniowanymi obiektami obejmującymi cały proces (np. Rejestracja), są na ogół w porządku do wykorzystania jako dane globalne. Dane konfiguracyjne, szczególnie jeśli znajdują się w lokalnym pliku, należą do tej samej kategorii (jest tylko jeden plik dla całego procesu/aplikacji, podobny do logowania).

Ogólnie rzecz biorąc, jeśli zauważysz, że musisz przekazać dodatkowe argumenty, aby przekazać je innej funkcji, powinieneś wyciągnąć tę funkcję "w górę" i mieć inną, która pośredniczy. Innym, bardziej praktycznym podejściem, które to ilustruje, jest rozwój oparty na testach, ponieważ zmusza do przejścia w zależnościach.

Innym sposobem myślenia o tym jest: jeśli funkcja ta nie może łatwo poznać wszystkich szczegółów, aby wywołać podfunkcję, należy podciągnąć pod-funkcję do góry i wymusić wyższą, bardziej znaną warstwę, aby uzyskać potrzebne Informacja. Odkryłem, że ta technika jest wysoce przewodząca dla jakości kodu, ponieważ buduje podzielone na sekcje części, zamiast monolitycznych bestii.

W przykładzie na temat Active Directory, zamiast przechodząc wokół argumentów do ad_connect, przechodzą wokół obiektu, który obsługuje niezbędną logikę, to mają funkcję, która pośredniczy w interakcji między tym obiekcie i funkcję używając go

def create_user(name, ad_user, ad_pass, ad_ou, ...): 
    conn = ad_connect(ad_user, ad_pass, ...) 
    conn.CreateRecord(ad_user) 

def create_user_mediator(name, ad_controller): 
    ad_controller.CreateRecord("cn=%s" % name) 

To tylko jeden sposób robienia tego i oczywiście ma swoje wady i zalety. Jest to tylko przykład tego, jak można uniknąć konieczności stosowania zmiennych globalnych.

Powiązane problemy