Słyszałem, jak fraza jest rzucana na ziemię i dla mnie argumenty brzmią całkowicie szalone (przepraszam, jeśli mam tu słomkę, to nie moja intencja), ogólnie rzecz biorąc idzie coś w stylu:
Nie chcesz tworzyć abstrakcji, zanim dowiesz się, jaki jest ogólny przypadek, w przeciwnym razie (1) możesz umieszczać w swoich abstrakcjach rzeczy, które nie należą, lub (2) pomijając rzeczy ważne.
(1) Dla mnie brzmi to tak, jakby programista nie był wystarczająco pragmatyczny, przyjęli założenia, że w ostatecznym programie coś by nie istniało, więc pracują z niskim poziomem abstrakcji, problem nie jest przedwczesna abstrakcja, to przedwczesna konkrecja.
(2) Pominięcie ważnych rzeczy jest jedną rzeczą, jest całkowicie możliwe, że coś zostało pominięte w specyfikacji, która później okaże się ważna, rozwiązaniem tego nie jest wymyślenie własnej konkrecji i marnowanie zasobów, kiedy się dowiesz źle się domyśliłem, aby uzyskać więcej informacji od klienta.
Zawsze powinniśmy pracować od abstrakcji po konkrecje, ponieważ jest to najbardziej pragmatyczny sposób robienia rzeczy, a nie na odwrót.
Jeśli tego nie zrobimy, ryzykujemy nieporozumienie klientów i tworzenie rzeczy, które należy zmienić, ale jeśli zbudujemy tylko abstrakcje zdefiniowane przez klientów w ich własnym języku, nigdy nie narażymy się na to ryzyko (przynajmniej nie jest tak prawdopodobne, jak podjęcie strzał w ciemność z pewną konkrecją), tak, możliwe, że klienci zmieniają zdanie na temat szczegółów, ale abstrakcje, których używali, aby przekazać to, czego chcą, nadal są aktualne.
Oto przykład, powiedzmy, że klient życzy sobie stworzenia robota do pakowania przedmiotów:
public abstract class BaggingRobot() {
private Collection<Item> items;
public abstract void bag(Item item);
}
Budujemy coś na podstawie abstrakcji, których używał klient, bez wchodzenia w szczegóły z rzeczami, których nie znamy. Jest to niezwykle elastyczne, widziałem to nazywane „przedwczesną abstrakcją”, podczas gdy w rzeczywistości bardziej przedwczesne byłoby zakładanie, jak realizowany jest workowanie, powiedzmy po rozmowie z klientem, że chcą, aby więcej niż jeden przedmiot był pakowany jednocześnie . Aby zaktualizować moją klasę, wystarczy zmienić podpis, ale dla kogoś, kto zaczął od podstaw, może to wymagać dużego przeglądu systemu.
Nie ma czegoś takiego jak przedwczesna abstrakcja, tylko przedwczesna konkrecja. Co jest złego w tym stwierdzeniu? Gdzie są wady mojego rozumowania? Dzięki.
Odpowiedzi:
Przynajmniej moim zdaniem przedwczesna abstrakcja jest dość powszechna i była szczególnie wczesna w historii OOP.
Przynajmniej z tego, co zobaczyłem, głównym problemem, który się pojawił, było to, że ludzie czytali typowe przykłady hierarchii obiektowych. Powiedziano im dużo o przygotowaniu wszystkiego, aby poradzić sobie z przyszłymi zmianami, które mogą się pojawić (nawet jeśli nie było szczególnie dobrego powodu, by wierzyć, że tak się stanie). Innym tematem wspólnym dla wielu artykułów przez pewien czas były rzeczy takie jak dziobak, który łamie proste zasady dotyczące „wszystkie ssaki są takie” lub „wszystkie ptaki są takie”.
W rezultacie doszliśmy do kodu, który naprawdę musiał obsługiwać, powiedzmy, zapisy pracowników, ale został starannie napisany, aby był gotowy, jeśli kiedykolwiek wynająłeś pajęczaka lub może skorupiaka.
źródło
Ważne jest, aby pamiętać, że abstrakcja jest środkiem do celu. Używasz abstrakcji, aby ujednolicić zachowanie w swoim programie i sprawia, że dodawanie nowych klas jest proste w przypadkach, w których spodziewałbyś się, że zostaną dodane nowe klasy, ale tylko wtedy, gdy abstrakcja jest potrzebna w tym momencie.
Nie dodawałbyś abstrakcji tylko dlatego, że może być potrzebna (bez prawdziwej podstawy do myślenia, że będziesz musiał dodać nowe klasy w przyszłości). Właściwą metaforą może być hydraulika. Mamy nadzieję, że zgodzisz się, że 6-kierunkowa rura, która umożliwia przepływ wody w górę / w dół, wschód / zachód, północ / południe, będzie najbardziej elastycznym rodzajem rury, jaką możesz mieć. Teoretycznie możesz użyć 6-kierunkowej rury w dowolnym miejscu, w której jest wymagana rura, i zablokować niepotrzebne kierunki, prawda?
Jeśli spróbujesz naprawić problem z wyciekiem pod zlewem i odkryjesz, że wszystkie odcinki rury to 6-kierunkowe kawałki rur, z frustracją wyciągnij włosy na faceta, który tak zaprojektował. Nie tylko nie wiesz, gdzie jest problem, ale prawie na pewno łatwiej byłoby zacząć od zera we właściwy sposób.
Oczywiście kodowanie nie jest hydrauliką, ale metafora wciąż istnieje. Abstrakcja jest jak użycie tych 6-kierunkowych elementów rurowych. Używaj ich, jeśli szczerze wierzysz, że w najbliższej przyszłości może być konieczne połączenie rur ze wszystkich 6 kierunków. W przeciwnym razie abstrakcja jest po prostu komplikacją, niewiele różniącą się od stosowania wzorca, w którym nic nie jest wymagane, lub używania klasy boga, która próbuje zrobić wszystko. Jeśli nie jest używany i prawdopodobnie nigdy nie będzie używany, ostatecznie dodajesz dodatkową klasę za nic.
Trzeba przyznać, że sztuka pisania programów jest bardzo abstrakcyjna koncepcyjnie. Po prostu warto wspomnieć, że abstrakcje nie istnieją ze względu na to, że są abstrakcją, ale dlatego, że są praktyczne w jakiś realny sposób. Jeśli czujesz potrzebę korzystania z abstrakcji, niech tak będzie, ale nie proś mnie, abym później sprawdził Twoją instalację wodociągową. ;)
źródło
class
skoncentrowany… Nawet jeśli istnieje wiele klas, abstrakcja nie jest ograniczona do użycia w nich / czerpania z nich korzyści.Gdy wiele lat temu dowiedziałem się o analizie i projektowaniu obiektowym, zaczniemy od prostego angielskiego opisu systemu, którego potrzebował klient.
Przeglądając to, każdy rzeczownik (lub fraza rzeczownikowa) byłby uważany za możliwą klasę. Wszelkie czasowniki (lub frazy czasowników) byłyby potencjalnymi metodami na zajęciach. Tak więc „robot workujący” może być klasą
BaggingRobot
. „Otwórz torbę” może stać się metodąOpenBag
.Po kilku iteracjach zmieni się to w diagram klasowy.
W tym momencie nie ma klas abstrakcyjnych. Klient nie chce abstrakcyjnej koncepcji robota do workowania. Chcą robota, który wkłada rzeczy do worków. Wszystkie klasy są konkretne i mają zestaw metod.
Klasy abstrakcyjne są wprowadzane tylko wtedy, gdy staje się jasne, że:
Według mnie „przedwczesna abstrakcja” zakłada, że każdy
BaggingRobot
musi odziedziczyć po niektórychBaseRobot
, a co gorsza, próbować opracować zestaw metod,BaseRobot
zanim zdążysz wiedzieć, co jest wspólne dla wszystkich robotów.źródło
Brzmi to trochę tak, jakbyś chciał rozwiązać problem, który jeszcze nie istnieje, i że nie masz uzasadnionego powodu, aby przypuszczać, że wystąpi, chyba że po prostu uważasz, że klient nie ma racji co do żądania. W takim przypadku zaleciłbym większą komunikację niż implementację domyślnego rozwiązania, abstrakcyjnego lub innego. Choć może wydawać się nieszkodliwe po prostu klapnięcie „streszczenia” definicji klasy i czuć się bezpiecznie wiedząc, że możesz ją później rozszerzyć, może się okazać, że nigdy nie musisz tego robić, lub możesz rozszerzyć ją w sposób, który nadmiernie komplikuje projekt linia, poprzez abstrakcję niewłaściwych rzeczy.
Idąc za przykładem, czy wyobrażasz sobie, że to sam robot , pakowane przedmioty lub metoda pakowania zmieniają się wzdłuż linii?
Przedwczesna abstrakcja oznacza po prostu, że nie masz dobrego powodu, aby ją wykonywać, a ponieważ abstrakcje są dalekie od darmowych w wielu językach, możesz ponosić koszty ogólne bez uzasadnienia.
Edytuj Aby odpowiedzieć na niektóre punkty OP w komentarzach, aktualizuję to, aby wyjaśnić i odpowiedzieć w sposób, który nie wymaga długiego łańcucha komentarzy, a dokładniej odnosząc się do punktów (1) i (2).
(Podkreśl moje). Zakładając, że w ostatecznym programie istniałyby rzeczy, które nie są dokładnie tym, co widzę w twoim przykładzie. Klient poprosił o robota do pakowania przedmiotów. To bardzo specyficzna prośba, choć nieco niejasna w swoim języku. Klient chce robota, który pakuje przedmioty, więc produkujesz parę przedmiotów
Twój model jest prosty i precyzyjny, spełnia wymagania określone przez klienta, nie zwiększając złożoności rozwiązania i nie zakładając, że klient chciał więcej, niż prosił. Jeśli przedstawione w ten sposób wyjaśnią potrzebę posiadania przez robota wymiennych mechanizmów workowania, tylko wtedy masz wystarczającą ilość informacji, aby uzasadnić utworzenie interfejsu lub innej metody abstrakcji, ponieważ możesz teraz wskazać konkretną wartość dodaną do system poprzez abstrakcję.
Wręcz przeciwnie, jeśli zaczniesz od abstrakcji od czystego pragmatyzmu, albo spędzasz czas na tworzeniu osobnego interfejsu i wdrażaniu go w konkrecji, albo tworzysz klasę abstrakcyjną, lub dowolny inny sposób abstrakcji, jaki ci się podoba. Jeśli okaże się, że klient jest z tego zadowolony, a dalsze przedłużanie nie jest konieczne, na próżno spędziłeś czas i zasoby i / lub wprowadziłeś do systemu koszty ogólne i złożoność bez żadnego zysku.
W odniesieniu do (2) zgadzam się, że pominięcie ważnych kwestii nie jest na pierwszy rzut oka znakiem przedwczesnej abstrakcji. Abstrakcja czy nie, możesz pominąć coś ważnego i jeśli nie zostanie znaleziona daleko w linii łańcucha abstrakcji, nie będzie trudniej ani łatwiej to rozwiązać.
Zamiast tego interpretuję to jako oznaczające, że każda abstrakcja stwarza ryzyko zaciemnienia modelu domeny. Niepoprawna abstrakcja może sprawić, że system będzie bardzo trudny do uzasadnienia, ponieważ tworzysz relacje, które mogą drastycznie wpłynąć na dalszy rozwój modelu domeny i zrozumienie domeny. Ryzykujesz pominięcie nieistotnych informacji na temat abstrakcji , ale całego systemu , biorąc swój model do niewłaściwej króliczej nory.
źródło