Poniższy scenariusz przytrafił mi się kilka razy.
Zaprogramowałem algorytm, który rozwiązuje pewien problem. Działa dobrze i znajduje właściwe rozwiązania. Teraz chcę mieć możliwość powiedzenia algorytmowi „napisz pełne wyjaśnienie, w jaki sposób dotarłeś do rozwiązania”. Moim celem jest umiejętność korzystania z algorytmu podczas demonstracji online, zajęć instruktażowych itp. Nadal chcę mieć możliwość uruchamiania algorytmu w czasie rzeczywistym, bez wyjaśnień. Jakiego wzorca projektowego należy użyć?
PRZYKŁAD: Załóżmy, że wdrażam tę metodę w celu znalezienia największego wspólnego dzielnika . Aktualnie wdrożona metoda zwraca poprawną odpowiedź, ale bez wyjaśnień. Chcę mieć opcję wyjaśniającą jej metodę, na przykład:
Initially, a=6 and b=4. The number of 2-factors, d, is initialized to 0.
a and b are both even, so we divide them by 2 and increment d by 1.
Now, a=3 and b=2.
a is odd but b is even, so we divide b by 2.
Now, a=3 and b=1.
a and b are both odd, so we replace a by (a-b)/2 = 1.
Now, a=1 and b=1.
a=b, so the GCD is a*2^d = 2.
Dane wyjściowe powinny zostać zwrócone, aby można je było łatwo wyświetlić zarówno w konsoli, jak i aplikacjach internetowych.
Jaki jest dobry wzorzec dostarczania wyjaśnień, gdy jest to potrzebne, bez uszczerbku dla wydajności algorytmu w czasie rzeczywistym, gdy wyjaśnienia nie są potrzebne?
źródło
Dobrym wzorem jest Obserwator. https://en.wikipedia.org/wiki/Observer_pattern
W swoim algorytmie, w każdym punkcie, w którym chcesz coś wyprowadzić, powiadamiasz niektórych obserwatorów. Następnie decydują, co zrobić, czy to wysyłać tekst na konsoli, czy wysłać go do silnika HTML / Apache itp.
W zależności od języka programowania mogą istnieć różne sposoby na szybkie. Na przykład w Javie (traktuj to jako pseudokod, dla zwięzłości; uczynienie go „poprawnym”, z getterami, setterami, pozostawia się czytelnikowi):
Jest to nieco szczegółowe, ale czekanie
==null
powinno być tak szybkie, jak to możliwe.(Zauważ, że w ogólnym przypadku
observer
prawdopodobnie byłobyVector observers
zamiast tego pozwolić na więcej niż jednego obserwatora; jest to oczywiście również możliwe i nie doprowadzi do większego obciążenia; nadal możesz wprowadzić optymalizację, którą ustawiłeśobservers=null
zamiast mieć pustyVector
.)Oczywiście wdrażasz różne rodzaje obserwatorów w zależności od tego, co chcesz osiągnąć. Możesz także umieścić tam statystyki czasowe itp. Lub zrobić inne wymyślne rzeczy.
źródło
Jako niewielką poprawę prostego rejestrowania, stwórz obiekt, który modeluje jedno wykonanie algorytmu. Dodaj „krok” do tego obiektu kontenera za każdym razem, gdy kod zrobi coś interesującego. Na końcu algorytmu zaloguj zakumulowane kroki z kontenera.
Ma to kilka zalet:
EDYCJA: Jak skomentowali inni, lambdas mają narzut, więc trzeba by przeprowadzić test porównawczy, aby upewnić się, że ten narzut jest mniejszy niż niepotrzebna ocena kodu wymagana do skonstruowania ciągu dziennika (wpisy w dzienniku często nie są zwykłymi literałami, ale wymagają uzyskania informacji kontekstowych z obiekty uczestniczące).
źródło
Zwykle szukam rozgałęzień, co oznacza, że szukam instrukcji if. Ponieważ wskazują one, że oceniam wartość, która będzie kontrolować przepływ algorytmu. Przy każdym takim zdarzeniu (każdy warunek) mogę następnie zapisać wybraną ścieżkę i dlaczego została wybrana.
Więc w zasadzie rejestrowałbym wartości wejściowe (stan początkowy), każdą wybraną gałąź (warunki) i wartości podczas wchodzenia do wybranej gałęzi (stan tymczasowy).
źródło