Mam pewne surowe dane, które muszę zrobić wiele rzeczy (przesunąć, obrócić, przeskalować wzdłuż określonej osi, obrócić do ostatecznego położenia) i nie jestem pewien, jaki najlepszy sposób to zrobić, aby utrzymać czytelność kodu. Z jednej strony mogę wykonać jedną metodę z wieloma parametrami (10+), aby zrobić to, czego potrzebuję, ale jest to koszmar czytania kodu. Z drugiej strony mógłbym wykonać wiele metod z 1-3 parametrami, ale metody te trzeba by wywołać w bardzo konkretnej kolejności, aby uzyskać poprawny wynik. Przeczytałem, że najlepiej jest, aby metody zrobiły jedną rzecz i zrobiły to dobrze, ale wydaje się, że posiadanie wielu metod, które trzeba wywołać, otwiera kod dla trudnych do znalezienia błędów.
Czy jest jakiś paradygmat programowania, którego mógłbym użyć, który zminimalizowałby błędy i ułatwiłby odczytanie kodu?
źródło
Odpowiedzi:
Uwaga na czasowe połączenie . Jednak nie zawsze jest to problem.
Jeśli musisz wykonać kroki w kolejności, oznacza to, że krok 1 tworzy jakiś obiekt wymagany dla kroku 2 (np. Strumień pliku lub inna struktura danych). Tylko to wymaga, aby druga funkcja musiała być wywołana po pierwszej, nie jest nawet możliwe przypadkowe wywołanie ich w niewłaściwej kolejności.
Dzieląc swoją funkcjonalność na małe kawałki, każda część jest łatwiejsza do zrozumienia i zdecydowanie łatwiejsza do przetestowania w izolacji. Jeśli masz ogromną funkcję 100 linii i coś w środkowych przerwach, jak twój nieudany test powie ci, co jest nie tak? Jeśli jedna z pięciu metod linii ulegnie awarii, nieudany test jednostkowy natychmiast przekieruje cię do fragmentu kodu, który wymaga uwagi.
Tak powinien wyglądać złożony kod :
W dowolnym momencie podczas konwersji nieprzetworzonych danych do gotowego widgetu każda funkcja zwraca coś wymaganego na następnym etapie procesu. Nie można utworzyć stopu z żużla, najpierw należy go wytopić (oczyścić). Nie można utworzyć widgetu bez odpowiedniego zezwolenia (np. Stalowego) jako danych wejściowych.
Konkretne szczegóły każdego kroku zawarte są w poszczególnych funkcjach, które można przetestować: zamiast testowania jednostkowego całego procesu wydobywania skał i tworzenia widżetów, testuj każdy konkretny krok. Teraz masz łatwy sposób na upewnienie się, że jeśli proces tworzenia widgetu się nie powiedzie, możesz zawęzić konkretny powód.
Oprócz korzyści z testowania i sprawdzania poprawności, pisanie kodu w ten sposób jest znacznie łatwiejsze do odczytania. Nikt nie może zrozumieć ogromnej listy parametrów . Podziel go na małe kawałki i pokaż, co oznacza każdy mały kawałek: to można zaśmiecać .
źródło
Argument „należy wykonać w kolejności” jest dyskusyjny, ponieważ prawie cały kod musi być wykonywany we właściwej kolejności. W końcu nie możesz zapisać pliku, a następnie go otworzyć, a następnie zamknąć, prawda?
Powinieneś skoncentrować się na tym, co czyni twój kod najbardziej łatwym w utrzymaniu. Zazwyczaj oznacza to pisanie funkcji, które są małe i łatwe do zrozumienia. Każda funkcja powinna mieć jeden cel i nie mieć nieprzewidzianych skutków ubocznych.
źródło
Stworzyłbym » ImageProcesssor « (lub dowolną nazwę odpowiednią dla twojego projektu) oraz obiekt konfiguracyjny ProcessConfiguration , który przechowuje wszystkie niezbędne parametry.
Wewnątrz procesora obrazu zawarto cały proces za jednym mehtodem
process()
Metoda ta nazywa metod transformacyjnych w odpowiedniej kolejności
shift()
,rotate()
. Każda metoda pobiera odpowiednie parametry z przekazanej konfiguracji procesu .Użyłem płynnych interfejsów
co pozwala na dobrą inicjalizację (jak pokazano powyżej).
Oczywista zaleta polegająca na enkapsulacji niezbędnych parametrów w jednym obiekcie. Podpisy twojej metody stają się czytelne:
private void shift(Image i, ProcessConfiguration c)
Chodzi o przesuwanie się obrazu i szczegółowe parametry są w jakiś sposób skonfigurowane .
Alternatywnie możesz utworzyć ProcessingPipeline :
Wywołanie metody do metody
processImage
utworzyłoby instancję takiego potoku i uczyniło przezroczystym co i w jakiej kolejności jest wykonywana: przesunięcie , obrótźródło
Czy zastanawiałeś się nad jakimś curry ? Wyobraź sobie, że masz klasę
Processee
i klasęProcessor
:Teraz możesz zastąpić klasę
Processor
dwiema klasamiProcessor1
iProcessor2
:Następnie możesz wywoływać operacje we właściwej kolejności, używając:
Możesz zastosować ten wzór wiele razy, jeśli masz więcej niż dwa parametry. Możesz także grupować argumenty według własnego uznania, tzn. Nie trzeba, aby każda
process
metoda pobierała dokładnie jeden argument.źródło