Interfejsy
Trudno zrozumieć cel narzędzia, które rozwiązuje problem, którego nigdy nie miałeś. Nie rozumiałem interfejsów przez jakiś czas po rozpoczęciu programowania. Zrozumiemy, co zrobili, ale nie wiedziałem, dlaczego chcesz z nich skorzystać.
Oto problem - wiesz, co chcesz zrobić, ale masz na to wiele sposobów lub możesz zmienić sposób, w jaki to zrobisz później. Byłoby miło, gdybyś mógł wcielić się w rolę nieświadomego menedżera - wydawać zamówienia i osiągać pożądane wyniki bez dbania o to, jak to się robi.
Załóżmy, że masz małą witrynę internetową i zapisujesz wszystkie informacje o swoich użytkownikach w pliku csv. Nie jest to najbardziej wyrafinowane rozwiązanie, ale działa wystarczająco dobrze, aby przechowywać dane użytkownika twojej mamy. Później Twoja strona startuje i masz 10 000 użytkowników. Może nadszedł czas, aby użyć odpowiedniej bazy danych.
Gdybyś na początku był sprytny, zobaczyłbyś, że to nadchodzi, i nie wykonałeś połączeń, aby zapisać bezpośrednio w csv. Zamiast tego pomyślałbyś o tym, co musisz zrobić, bez względu na to, jak to zostało zaimplementowane. Powiedzmy store()
i retrieve()
. Państwo dokonać Persister
interfejs z abstrakcyjnych metod store()
i retrieve()
i utworzyć CsvPersister
podklasę że faktycznie implementuje te metody.
Później możesz utworzyć plik, DbPersister
który implementuje faktyczne przechowywanie i pobieranie danych zupełnie inaczej niż w przypadku klasy csv.
Wspaniałą rzeczą jest to, że wszystko, co musisz teraz zrobić, to zmienić
Persister* prst = new CsvPersister();
do
Persister* prst = new DbPersister();
i gotowe. Twoje wezwania do prst.store()
i prst.retrieve()
nadal będą działać, są po prostu inaczej przetwarzane „za kulisami”.
Teraz nadal musiałeś tworzyć implementacje cvs i db, więc nie doświadczyłeś jeszcze luksusu bycia szefem. Rzeczywiste korzyści są widoczne, gdy używasz interfejsów utworzonych przez kogoś innego. Jeśli ktoś inny był na tyle uprzejmy, aby stworzyć CsvPersister()
i DbPersister()
już, to wystarczy wybrać jeden i wywołać niezbędne metody. Jeśli zdecydujesz się użyć drugiego później lub w innym projekcie, już wiesz, jak to działa.
Jestem naprawdę zardzewiały na moim C ++, więc użyję tylko ogólnych przykładów programowania. Kontenery są doskonałym przykładem tego, jak interfejsy ułatwiają życie.
Możesz mieć Array
, LinkedList
, BinaryTree
, z itp wszystkie podklasy Container
, która ma metody, takie jak insert()
, find()
, delete()
.
Teraz, gdy dodajesz coś na środku połączonej listy, nie musisz nawet wiedzieć, czym jest połączona lista. Wystarczy zadzwonić, myLinkedList->insert(4)
a magicznie iteruje się po liście i umieszcza ją tam. Nawet jeśli wiesz, jak działa połączona lista (co naprawdę powinieneś), nie musisz sprawdzać jej konkretnych funkcji, ponieważ prawdopodobnie już wiesz, co to za korzystanie z innej Container
wcześniej.
Klasy abstrakcyjne
Klasy abstrakcyjne są bardzo podobne do interfejsów (technicznie interfejsy są klasami abstrakcyjnymi, ale tutaj mam na myśli klasy podstawowe, które mają rozwinięte niektóre z ich metod.
Załóżmy, że tworzysz grę i musisz wykryć, kiedy wrogowie znajdują się w odległości uderzenia gracza. Możesz utworzyć klasę podstawową, Enemy
która ma metodę inRange()
. Chociaż istnieje wiele różnych cech przeciwników, metoda sprawdzania ich zasięgu jest spójna. Dlatego twoja Enemy
klasa będzie miała dopracowaną metodę sprawdzania zasięgu, ale czyste metody wirtualne dla innych rzeczy, które nie mają podobieństw między typami wroga.
Zaletą jest to, że jeśli zepsujesz kod wykrywania zasięgu lub chcesz go ulepszyć, musisz go zmienić tylko w jednym miejscu.
Oczywiście istnieje wiele innych powodów interfejsów i abstrakcyjnych klas bazowych, ale są to niektóre powody, dla których możesz z nich korzystać.
Singletony
Używam ich od czasu do czasu i nigdy mnie nie spalili. Nie oznacza to, że w pewnym momencie nie zrujnują mi życia na podstawie doświadczeń innych ludzi.
Oto dobra dyskusja na temat stanu globalnego od bardziej doświadczonych i ostrożnych ludzi:
Dlaczego państwo globalne jest tak złe?