Zakładając, że mam ten pseudo-kod:
bool conditionA = executeStepA();
if (conditionA){
bool conditionB = executeStepB();
if (conditionB){
bool conditionC = executeStepC();
if (conditionC){
...
}
}
}
executeThisFunctionInAnyCase();
Funkcje executeStepX
powinny być wykonywane tylko wtedy, gdy poprzednie zakończyły się powodzeniem. W każdym razie executeThisFunctionInAnyCase
funkcja powinna zostać wywołana na końcu. Jestem początkującym programistą, przepraszam za bardzo podstawowe pytanie: czy istnieje sposób (na przykład w C / C ++), aby uniknąć tego długiego if
łańcucha produkującego coś w rodzaju „piramidy kodu” kosztem czytelności kodu ?
Wiem, że gdybyśmy mogli pominąć executeThisFunctionInAnyCase
wywołanie funkcji, kod mógłby zostać uproszczony jako:
bool conditionA = executeStepA();
if (!conditionA) return;
bool conditionB = executeStepB();
if (!conditionB) return;
bool conditionC = executeStepC();
if (!conditionC) return;
Ale ograniczeniem jest executeThisFunctionInAnyCase
wywołanie funkcji. Czy break
można w jakiś sposób wykorzystać to oświadczenie?
c++
c
if-statement
control-flow
ABCplus
źródło
źródło
false
można uznać za coś wyjątkowego?false
Powrót może być całkiem normalne.Odpowiedzi:
Możesz użyć
&&
(logika AND):spełni to oba Twoje wymagania:
executeStep<X>()
powinien oceniać tylko, jeśli poprzedni się powiódł (nazywa się to oceną zwarcia )executeThisFunctionInAnyCase()
zostanie wykonane w każdym przypadkuźródło
&&
i||
), więc nie ma sposobu, aby połączyć je w jednąif
instrukcję bez pomniejszenia czytelności. Przeniesienie tych warunków do funkcji zewnętrznych nie zawsze jest łatwe, ponieważ mogą one zależeć od wielu wcześniej obliczonych zmiennych lokalnych, co spowodowałoby straszny bałagan, gdybyś spróbował przekazać każdy z nich jako osobny argument.Wystarczy użyć dodatkowej funkcji, aby uruchomić drugą wersję:
Użycie głęboko zagnieżdżonego ifs (twój pierwszy wariant) lub chęć wyjścia z „części funkcji” zwykle oznacza, że potrzebujesz dodatkowej funkcji.
źródło
foo
działa poprzez sekwencję powiązanych warunków i działań. Funkcjabar
jest wyraźnie oddzielona od decyzji. Gdybyśmy zobaczyli szczegóły warunków i działań, może się okazać, żefoo
wciąż robią za dużo, ale na razie jest to dobre rozwiązanie.bar
Ciebie, będziesz musiał ręcznie przekazać jefoo
jako parametry. Jeśli tak jest i jeślifoo
zostanie wywołane tylko raz, popełniłbym błąd w używaniu wersji goto, aby uniknąć zdefiniowania dwóch ściśle powiązanych funkcji, które ostatecznie nie byłyby bardzo przydatne.if (!executeStepA() || !executeStepB() || !executeStepC()) return
goto
W tym przypadku używają programiści starej szkoły C. Jest to jedyne użycie,goto
które tak naprawdę zachęca przewodnik po stylach Linuksa, zwane scentralizowanym wyjściem funkcji:Niektórzy ludzie pracują przy użyciu
goto
, zawijając ciało w pętlę i odrywając się od niego, ale skutecznie oba podejścia robią to samo.goto
Podejście jest lepsze, jeśli potrzebujesz jakieś inne porządki tylko jeśliexecuteStepA()
był udany:Przy podejściu pętli uzyskałbyś wtedy dwa poziomy pętli.
źródło
goto
i od razu myśli „To okropny kod”, ale ma swoje prawidłowe zastosowania.goto
i nawet nie muszę myśleć, że to okropny kod. Kiedyś musiałem takie utrzymywać, to bardzo paskudne. OP sugeruje rozsądną alternatywę dla języka C na końcu pytania i uwzględniłem to w mojej odpowiedzi.throw
jest pod wieloma względami gorsze niżgoto
dlatego,throw
że nie jest nawet jasne z lokalnego kontekstu, w którym skończysz! Zastosuj te same zasady projektowania dla przepływu sterowania w stylu goto, jak w przypadku wyjątków.Jest to powszechna sytuacja i istnieje wiele typowych sposobów radzenia sobie z nią. Oto moja próba kanonicznej odpowiedzi. Jeśli coś przeoczyłem, proszę o komentarz, a ten post będę aktualizowany na bieżąco.
To jest strzała
To, co omawiasz, nazywa się anty-wzorem strzałki . Nazywa się to strzałką, ponieważ łańcuch zagnieżdżonych ifs tworzy bloki kodu, które rozszerzają się coraz bardziej w prawo, a następnie z powrotem w lewo, tworząc strzałkę wizualną, która „wskazuje” na prawą stronę panelu edytora kodu.
Spłaszcz strzałę strażnikiem
Omówiono tutaj niektóre typowe sposoby unikania Strzałki . Najpopularniejszą metodą jest użycie wzorca zabezpieczającego , w którym kod obsługuje najpierw przepływy wyjątków, a następnie obsługuje przepływ podstawowy, np. Zamiast
... użyłbyś ...
Gdy jest długa seria strażników, spłaszcza to znacznie kod, ponieważ wszyscy strażnicy pojawiają się aż do lewej, a twoje nie są zagnieżdżone. Ponadto wizualnie parujesz warunek logiczny z powiązanym błędem, co znacznie ułatwia stwierdzenie, co się dzieje:
Strzałka:
Strzec:
Jest to obiektywnie i ilościowo łatwiejsze do odczytania, ponieważ
Jak dodać wspólny kod na końcu
Problem z wzorcem ochronnym polega na tym, że polega on na tak zwanym „oportunistycznym powrocie” lub „oportunistycznym wyjściu”. Innymi słowy, łamie to wzór, że każda funkcja powinna mieć dokładnie jeden punkt wyjścia. Jest to problem z dwóch powodów:
Poniżej przedstawiłem kilka opcji obejścia tego ograniczenia albo za pomocą funkcji językowych, albo całkowicie unikając problemu.
Opcja 1. Nie możesz tego zrobić: użyj
finally
Niestety, jako programista c ++, nie możesz tego zrobić. Jest to jednak odpowiedź numer jeden w przypadku języków, które zawierają słowo kluczowe, ponieważ właśnie po to jest.
Opcja 2. Uniknij problemu: zrestrukturyzuj swoje funkcje
Możesz uniknąć problemu, dzieląc kod na dwie funkcje. Rozwiązanie to ma tę zaletę, że działa w dowolnym języku, a dodatkowo może zmniejszyć złożoność cykliczną , co jest sprawdzonym sposobem na zmniejszenie liczby defektów i poprawia specyfikę zautomatyzowanych testów jednostkowych.
Oto przykład:
Opcja 3. Sztuczka językowa: użyj fałszywej pętli
Inną częstą sztuczką, którą widzę, jest używanie while (true) i break, jak pokazano w innych odpowiedziach.
Chociaż jest to mniej „uczciwe” niż używanie
goto
, jest mniej podatne na pomieszanie podczas refaktoryzacji, ponieważ wyraźnie wyznacza granice zakresu logiki. Naiwny programista, który wycina i wkleja etykiety lubgoto
oświadczenia, może powodować poważne problemy! (I szczerze mówiąc, ten wzór jest teraz tak powszechny, że myślę, że wyraźnie przekazuje intencję i dlatego nie jest wcale „nieuczciwy”).Istnieją inne warianty tej opcji. Na przykład można użyć
switch
zamiastwhile
.break
Prawdopodobnie działałby każdy konstrukt języka ze słowem kluczowym.Opcja 4. Wykorzystaj cykl życia obiektu
Jedno inne podejście wykorzystuje cykl życia obiektu. Użyj obiektu kontekstowego, aby przenieść parametry (coś, czego podejrzanie brakuje w naszym naiwnym przykładzie) i usuń je, gdy skończysz.
Uwaga: Upewnij się, że rozumiesz cykl życia obiektu w wybranym języku. Aby to zadziałało, potrzebujesz pewnego rodzaju deterministycznego wyrzucania elementów bezużytecznych, tzn. Musisz wiedzieć, kiedy zostanie wywołany destruktor. W niektórych językach będziesz musiał użyć
Dispose
zamiast destruktora.Opcja 4.1. Wykorzystaj cykl życia obiektu (wzór opakowania)
Jeśli zamierzasz zastosować podejście obiektowe, równie dobrze możesz to zrobić poprawnie. Ta opcja używa klasy do „zawijania” zasobów, które wymagają czyszczenia, a także innych operacji.
Ponownie upewnij się, że rozumiesz swój cykl życia obiektu.
Opcja 5. Sztuczka językowa: Użyj oceny zwarcia
Inną techniką jest skorzystanie z oceny zwarcia .
To rozwiązanie wykorzystuje sposób działania operatora &&. Kiedy lewa strona && ma wartość false, prawa strona nigdy nie jest oceniana.
Ta sztuczka jest najbardziej przydatna, gdy wymagany jest zwarty kod i gdy kod prawdopodobnie nie wymaga wiele konserwacji, np. Wdrażasz dobrze znany algorytm. Dla bardziej ogólnego kodowania struktura tego kodu jest zbyt krucha; nawet niewielka zmiana w logice może spowodować całkowite przepisanie.
źródło
Po prostu zrób
To takie proste.
Z powodu trzech edycji, z których każda zasadniczo zmieniła pytanie (cztery, jeśli liczy się zmiana z powrotem do wersji 1), dołączam przykład kodu, na który odpowiadam:
źródło
&&
lista jest znacznie jaśniejsza. Zwykle dzielę warunki na osobne linie i dodam// explanation
do nich każdy znak końcowy ... W końcu jest o wiele mniej kodu do oglądania, a kiedy zrozumiesz, jak&&
działa, nie ma ciągłego wysiłku umysłowego. Mam wrażenie, że większość profesjonalnych programistów C ++ byłaby z tym zaznajomiona, ale, jak mówisz w różnych branżach / projektach, nacisk i doświadczenie są różne.W C ++ istnieje sposób na odroczenie działań: użycie destruktora obiektu.
Zakładając, że masz dostęp do C ++ 11:
A następnie za pomocą tego narzędzia:
źródło
executeThisFunctionInAnyCase();
zostanie wykonany, nawet jeślifoo();
zgłosi wyjątek. Podczas pisania kodu bezpiecznego dla wyjątków dobrą praktyką jest umieszczenie wszystkich takich funkcji czyszczenia w destruktorze.foo()
. A jeśli to zrobisz, złap go. Problem rozwiązany. Napraw błędy, naprawiając je, a nie pisząc obejścia.Defer
klasa to mały fragment kodu wielokrotnego użytku, który pozwala na wykonanie dowolnego czyszczenia na końcu bloku, w wyjątkowo bezpieczny sposób. jest bardziej znany jako osłona zakresu . tak, każde użycie osłony zakresu może być wyrażone na inne, bardziej ręczne sposoby, tak jak każdafor
pętla może być wyrażona jako blok iwhile
pętla, które z kolei mogą być wyrażone za pomocąif
igoto
, które można wyrazić w języku asemblera, jeśli chcesz, lub dla tych, którzy są prawdziwymi mistrzami, poprzez zmianę bitów w pamięci za pomocą promieni kosmicznych kierowanych przez efekt motyla specjalnych krótkich pomruków i śpiewów. ale dlaczego to zrobić.Jest fajna technika, która nie wymaga dodatkowej funkcji otoki z instrukcjami return (metoda zalecana przez Itjax). Wykorzystuje
while(0)
pseudo-pętlę do. Wwhile (0)
zapewnia, że nie jest to faktycznie pętli ale wykonywane tylko raz. Jednak składnia pętli pozwala na użycie instrukcji break.źródło
inline
. W każdym razie jest to miła technika do poznania, ponieważ pomaga ona bardziej niż w tym problemie.Możesz także to zrobić:
W ten sposób masz minimalny rozmiar liniowego wzrostu, +1 linię na połączenie i jest łatwy do utrzymania.
EDYCJA : (Dzięki @Unda) Nie jest wielkim fanem, ponieważ tracisz widoczność IMO:
źródło
Czy to zadziała? Myślę, że jest to równoważne z twoim kodem.
źródło
ok
gdy używam tej samej zmiennej jak ta.Zakładając, że pożądany kod jest taki, jaki obecnie go widzę:
Powiedziałbym, że prawidłowe podejście, ponieważ jest najłatwiejsze do odczytania i najłatwiejsze w utrzymaniu, miałoby mniej poziomów wcięć, co jest (obecnie) podanym celem pytania.
W ten sposób unika jakichkolwiek potrzebę
goto
s, wyjątki, atrapywhile
pętlach lub innych trudnych konstrukcjach i po prostu wsiada z prostego zadania pod ręką.źródło
return
ibreak
wyskakiwanie z pętli bez konieczności wprowadzania dodatkowych zmiennych „flag”. W takim przypadku użycie goto byłoby podobnie niewinne - pamiętaj, że handlujesz dodatkową złożonością goto za dodatkową zmienną złożoność zmiennych.newbie
, zapewnia czystsze rozwiązanie bez wad. Zauważam, że również nie polega na tym,steps
że ma taką samą sygnaturę, a nawet jest funkcją, a nie blokiem. Widzę, że jest to stosowane jako refaktor pierwszego przejścia, nawet gdy bardziej wyrafinowane podejście jest ważne.Może nie jest to najlepsze rozwiązanie, ale możesz umieścić swoje instrukcje w
do .. while (0)
pętli i użyćbreak
instrukcji zamiastreturn
.źródło
do .. while (0)
do definicji makr również nadużywa pętli, ale jest uważane za OK.Możesz umieścić wszystkie
if
warunki, sformatowane tak, jak chcesz, w ich własnych funkcjach, a po powrocie wykonaćexecuteThisFunctionInAnyCase()
funkcję.Z podstawowego przykładu w PO, testowanie i wykonanie warunków można oddzielić jako takie;
A następnie nazywany jako taki;
Jeśli dostępne są lambdy C ++ 11 (w OP nie było tagu C ++ 11, ale nadal mogą być opcją), możemy zrezygnować z oddzielnej funkcji i zawinąć ją w lambda.
źródło
Jeśli nie lubisz
goto
i niedo { } while (0);
lubisz pętli i lubisz używać C ++, możesz również użyć tymczasowej lambda, aby uzyskać ten sam efekt.źródło
if
nie lubisz goto&&
nie lubisz robić {}, podczas gdy (0)&&
lubisz C ++ ... Przepraszam, nie mogłem się oprzeć, ale ten ostatni warunek nie udaje się, ponieważ pytanie jest oznaczone jako c oraz c ++Łańcuchy IF / ELSE w twoim kodzie nie są problemem językowym, ale projektem twojego programu. Jeśli jesteś w stanie zmienić lub ponownie napisać swój program, chciałbym zasugerować, aby zajrzeć do Wzorów projektowych ( http://sourcemaking.com/design_patterns ), aby znaleźć lepsze rozwiązanie.
Zwykle, gdy widzisz w kodzie wiele IF i innych, jest to okazja do zaimplementowania wzorca projektowania strategii ( http://sourcemaking.com/design_patterns/strategy/c-sharp-dot-net ) lub może kombinacji innych wzorów.
Jestem pewien, że istnieją alternatywy, aby napisać długą listę if / else, ale wątpię, aby coś zmieniły, z wyjątkiem tego, że łańcuch będzie wyglądał ładnie dla ciebie (Jednak piękno jest w oku patrzącego nadal dotyczy kodu też:-) ) . Powinieneś martwić się o takie rzeczy (czy w ciągu 6 miesięcy, kiedy mam nowy stan i nie pamiętam nic o tym kodzie, czy będę w stanie łatwo go dodać? Albo co, jeśli łańcuch się zmieni, jak szybko i bezbłędnie czy będę go wdrażać)
źródło
Po prostu to zrób ...
99 razy na 100, to jedyny sposób, aby to zrobić.
Nigdy, nigdy, nigdy nie próbuj robić czegoś „podstępnego” w kodzie komputerowym.
Nawiasem mówiąc, jestem prawie pewien, że poniższe rozwiązanie jest właściwym rozwiązaniem, o którym myślisz ...
Instrukcja kontynuacji ma kluczowe znaczenie w programowaniu algorytmicznym. (O ile instrukcja goto ma kluczowe znaczenie w programowaniu algorytmicznym).
W wielu językach programowania możesz to zrobić:
(Uwaga: przede wszystkim: nagie bloki jak ten przykład są kluczową i ważną częścią pisania pięknego kodu, szczególnie jeśli masz do czynienia z programowaniem „algorytmicznym”).
Znów dokładnie to miałeś w głowie, prawda? I to jest piękny sposób na napisanie tego, więc masz dobry instynkt.
Jednak tragicznie w obecnej wersji celu-c (na bok - nie wiem o Swift, przepraszam) istnieje pewna sensowna funkcja, która sprawdza, czy blok otaczający jest pętlą.
Oto jak obejść ten problem ...
Więc nie zapominaj o tym ...
do {} while (false);
oznacza po prostu „zrób ten blok raz”.
tzn. nie ma żadnej różnicy między pisaniem
do{}while(false);
a zwykłym pisaniem{}
.To działa teraz idealnie, jak chciałeś ... oto wynik ...
Możliwe więc, że tak właśnie widzisz algorytm w swojej głowie. Zawsze powinieneś próbować pisać to, co masz w głowie. (Zwłaszcza jeśli nie jesteś trzeźwy, bo wtedy pojawia się śliczna! :))
W projektach „algorytmicznych”, w których często się to zdarza, w celu-c zawsze mamy makro takie jak ...
... więc możesz to zrobić ...
Istnieją dwa punkty:
a, chociaż to głupie, że cel-c sprawdza rodzaj bloku, w którym znajduje się instrukcja kontynuacji, trudno jest z tym „walczyć”. To trudna decyzja.
b, jest pytanie, czy powinieneś wciąć w tym przykładzie blok? Nie mogę zasnąć z powodu takich pytań, więc nie mogę doradzić.
Mam nadzieję, że to pomoże.
źródło
if
, możesz również użyć bardziej opisowych nazw funkcji i umieścić komentarze w funkcjach.Niech twoje funkcje wykonywania zgłoszą wyjątek, jeśli zawiodą, zamiast zwracać wartość false. Wówczas Twój kod telefoniczny może wyglądać następująco:
Oczywiście zakładam, że w twoim oryginalnym przykładzie krok wykonania zwróci fałsz tylko w przypadku wystąpienia błędu w kroku?
źródło
Wiele dobrych odpowiedzi już, ale wydaje się, że większość z nich kompromituje niektóre (co prawda bardzo mało) elastyczności. Powszechnym podejściem, które nie wymaga tego kompromisu, jest dodawanie zmiennej status / keep-go . Cena jest oczywiście jedną dodatkową wartością do śledzenia:
źródło
ok &= conditionX;
nie po prostuok = conditionX;
?W C ++ (pytanie jest oznaczone zarówno C, jak i C ++), jeśli nie możesz zmienić funkcji w celu użycia wyjątków, nadal możesz użyć mechanizmu wyjątku, jeśli napiszesz małą funkcję pomocniczą, taką jak
Wówczas Twój kod mógłby brzmieć następująco:
Jeśli lubisz fantazyjną składnię, możesz zamiast tego sprawić, by działała za pomocą jawnej obsady:
Następnie możesz napisać kod jako
źródło
Jeśli Twój kod jest tak prosty jak Twój przykład, a Twój język obsługuje oceny zwarć, możesz spróbować:
Jeśli przekazujesz argumenty do swoich funkcji i odzyskujesz inne wyniki, aby Twój kod nie mógł zostać zapisany w poprzedni sposób, wiele innych odpowiedzi lepiej pasowałoby do problemu.
źródło
W przypadku C ++ 11 i nowszych fajnym podejściem może być wdrożenie systemu wyjścia zakresu podobnego do mechanizmu zasięgu (wyjścia) D.
Jednym z możliwych sposobów jego implementacji jest użycie lambda C ++ 11 i niektórych makr pomocniczych:
Pozwoli ci to wrócić wcześniej z funkcji i upewnić się, że kod czyszczenia, który zdefiniujesz, jest zawsze wykonywany po wyjściu z zakresu:
Makra to tak naprawdę dekoracja.
MakeScopeExit()
może być używany bezpośrednio.źródło
[=]
zwykle jest źle w przypadku lambda z lunetą.[&]
: jest bezpieczna i minimalnie zaskakująca. Przechwytywanie według wartości tylko wtedy, gdy lambda (lub kopie) może przetrwać dłużej niż zakres w punkcie deklaracji ...Dlaczego nikt nie podaje najprostszego rozwiązania? :RE
Jeśli wszystkie funkcje mają ten sam podpis, możesz to zrobić w ten sposób (dla języka C):
Aby uzyskać czyste rozwiązanie C ++, należy utworzyć klasę interfejsu, która zawiera metodę wykonania i zawija kroki w obiektach.
Następnie powyższe rozwiązanie będzie wyglądać następująco:
źródło
Zakładając, że nie potrzebujesz indywidualnych zmiennych warunkowych, odwrócenie testów i użycie opcji else-falthrough jako ścieżki „ok” pozwoliłoby uzyskać bardziej pionowy zestaw instrukcji if / else:
Pominięcie nieudanej zmiennej powoduje, że kod jest zbyt niejasny dla IMO.
Zadeklarowanie zmiennych wewnątrz jest w porządku, nie martw się o = vs ==.
Jest to niejasne, ale kompaktowe:
źródło
Wygląda to na automat stanowy, co jest przydatne, ponieważ można go łatwo zaimplementować za pomocą wzorca stanu .
W Javie wyglądałoby to mniej więcej tak:
Implementacja będzie działać w następujący sposób:
I tak dalej. Następnie możesz zastąpić duży warunek jeśli:
źródło
Jak wspomniał Rommik, możesz zastosować do tego wzór projektowy, ale wolałbym użyć wzoru Dekorator niż Strategii, ponieważ chcesz łączyć połączenia. Jeśli kod jest prosty, wybrałbym jedną z ładnie ustrukturyzowanych odpowiedzi, aby zapobiec zagnieżdżeniu. Jednak jeśli jest złożony lub wymaga dynamicznego łączenia, to wzór Dekoratora jest dobrym wyborem. Oto schemat klas yUML :
Oto przykładowy program LinqPad C #:
Najlepsza książka do przeczytania na temat wzorów projektowych, IMHO, to Head First Design Patterns .
źródło
Kilka odpowiedzi wskazywało na wzór, który widziałem i stosowałem wiele razy, szczególnie w programowaniu sieciowym. W stosach sieciowych często występuje długa sekwencja żądań, z których każde może zakończyć się niepowodzeniem i zatrzymać proces.
Powszechnym wzorem było użycie
do { } while (false);
Kiedyś makro dla
while(false)
abydo { } once;
Wspólna wzór był następujący:Ten wzorzec był stosunkowo łatwy do odczytania i pozwolił na użycie obiektów, które odpowiednio zniszczyłyby, a także uniknęły wielokrotnych zwrotów, co nieco ułatwiło wchodzenie i debugowanie.
źródło
Aby ulepszyć odpowiedź Mathieu na C ++ 11 i uniknąć kosztów środowiska wykonawczego związanych z użyciem
std::function
, sugerowałbym użycie następującychTa prosta klasa szablonów zaakceptuje dowolny funktor, który można wywołać bez żadnych parametrów, i robi to bez żadnych dynamicznych przydziałów pamięci, a zatem lepiej odpowiada celowi abstrakcji C ++ bez niepotrzebnego narzutu. Dodatkowy szablon funkcji ma na celu uproszczenie użycia przez odjęcie parametrów szablonu (które nie jest dostępne dla parametrów szablonu klasy)
Przykład użycia:
Podobnie jak odpowiedź Mathieu, to rozwiązanie jest w pełni bezpieczne i
executeThisFunctionInAnyCase
będzie wywoływane we wszystkich przypadkach. GdybyexecuteThisFunctionInAnyCase
się rzuciło, niszczyciele są domyślnie oznaczonenoexcept
i dlatego wywołanestd::terminate
zostanie polecenie zamiast wywoływać wyjątek podczas odwijania stosu.źródło
functor
wdeferred
konstruktorze, bez potrzeby wymuszaniamove
.Wygląda na to, że chcesz wykonywać wszystkie połączenia z jednego bloku. Jak inni to zaproponowali, powinieneś użyć
while
pętli i wyjść używającbreak
lub nowej funkcji, którą możesz zostawićreturn
(może być czystsza).Osobiście wypędzam
goto
, nawet za wyjście z funkcji. Są trudniejsze do wykrycia podczas debugowania.Elegancką alternatywą, która powinna działać w twoim przepływie pracy, jest zbudowanie tablicy funkcji i iteracja na niej.
źródło
Ponieważ masz również [... blok kodu ...] między wykonaniami, myślę, że masz alokację pamięci lub inicjalizację obiektu. W ten sposób musisz zadbać o wyczyszczenie wszystkiego, co już zainicjalizowałeś przy wyjściu, a także wyczyść go, jeśli napotkasz problem i którakolwiek z funkcji zwróci false.
W tym przypadku najlepsze, co miałem z mojego doświadczenia (kiedy pracowałem z CryptoAPI), to tworzenie małych klas, w konstruktorze inicjujesz swoje dane, w destruktorze - je inicjujesz. Każda następna klasa funkcji musi być potomkiem poprzedniej klasy funkcji. Jeśli coś poszło nie tak - wyrzuć wyjątek.
A następnie w kodzie wystarczy wywołać:
Myślę, że to najlepsze rozwiązanie, jeśli każde wywołanie ConditionX coś zainicjuje, przydzieli pamięć i tym podobne. Najlepiej mieć pewność, że wszystko zostanie wyczyszczone.
źródło
ciekawym sposobem jest praca z wyjątkami.
Jeśli napiszesz taki kod, idziesz w złym kierunku. Nie uważam tego za „problem” za taki kod, ale za taką bałaganiarską „architekturę”.
Wskazówka: przedyskutuj te sprawy z doświadczonym programistą, któremu ufasz ;-)
źródło
Inne podejście -
do - while
nawet jeśli zostało wspomniane wcześniej, nie było takiego przykładu, który pokazałby, jak to wygląda:(Cóż, istnieje już odpowiedź z
while
pętlą, aledo - while
pętla nie sprawdza nadmiarowo prawdy (na początku), ale zamiast tego na końcu xD (można to jednak pominąć)).źródło