Czy są znane wzorce projektowe do wdrażania modeli zniżek?
Mówiąc o modelach rabatowych mam na myśli:
Jeśli klient kupi Produkt X, Produkt Y i Produkt Z, otrzyma rabat w wysokości 10% lub 100 USD.
Jeśli klient kupi 100 jednostek produktu X, otrzyma rabat w wysokości 15% lub 500 USD
Jeśli klient przyniósł w ubiegłym roku więcej niż 100 000 USD, otrzymuje stałą 20% zniżkę
Jeśli klient kupił 2 jednostki produktu X, otrzymuje 1 jednostkę produktu X (lub produktu Y) za darmo.
...
Czy istnieje ogólny wzorzec, który można zastosować do obsługi wszystkich powyższych scenariuszy? Mam na myśli kilka modeli, ale nie mogę znaleźć jednego ogólnego.
design
design-patterns
financial
Kanini
źródło
źródło
Odpowiedzi:
Jeśli problem polega na tym, że musisz zastosować wiele rabatów, w danych okolicznościach możesz rozważyć wzorzec łańcucha odpowiedzialności .
W skrócie, przekazujesz informacje, które chcesz przetworzyć, do pierwszego procesora i od tego momentu decydujesz, czy przekazać je kolejnym procesorom przed zwróceniem wyniku.
W ten sposób możesz zmienić strukturę i sekwencję procesorów bez zmiany kodu wywołującego.
źródło
Wzory strategii, dekoratora i stanu wyróżniają się jako potencjalne punkty wyjścia. Stan może być szczególnie użyteczny dla 2 lub 3, ponieważ 2 zależy od stanu zamówienia, a 3 zależy od stanu klienta w określonym przedziale czasu. Strategia i Dekorator wyróżniają się na tle innych, ponieważ można użyć strategii do wdrożenia wielu algorytmów obliczania ceny zamówienia i Dekoratora, aby dodać nowe rabaty do zamówienia.
Pamiętaj jednak, że wzorce projektowe to tylko modele. Może nie obowiązywać pojedynczy wzorzec, ale raczej system wzorców. Zastanów się również nad modyfikacjami opisanych modeli, aby lepiej pasowały do twojego rozwiązania. Lepiej mieć dobry projekt niż wymuszać wzór, w którym niekoniecznie pomaga to tylko dlatego, że można powiedzieć, że masz wzór.
źródło
Cóż, zaprojektowałbym model rabatu jako parę „Warunek wstępny” i „Rabat”, gdzie „Warunek wstępny” to klasa z metodami
albo i
i Rabat ma metodę
void ApplyTo(Customer c)
. Daje to możliwość połączenia dowolnego rodzaju warunku wstępnego z dowolnym rodzajem rabatu (myślę, że jest to forma „wzorca pomostowego”).Jeśli masz określoną liczbę warunków wstępnych, możesz rozwiązać problem, budując określone podtypy (wzorzec strategii). Jednak gdy twoje warunki wstępne mogą być bardzo złożone, z logicznymi stwierdzeniami, takimi jak AND, OR i NOT, możesz lepiej zaimplementować jakiś interpretator reguł dla warunków. Reguły mogą być zwykłym ciągiem tekstowym napisanym prostym „językiem specyficznym dla domeny”.
To samo dotyczy klasy „Rabat”, możesz albo mieć pewne podtypy dla różnych rodzajów rabatów, albo ogólne podejście, w którym reguły rabatów są podawane w formie tekstowej, oceniane przez jakiegoś tłumacza.
źródło
Prawdopodobnie potrzebujesz interfejsu IDiscount, ponieważ wszystkie różne rabaty są takie same i będziemy chcieli traktować je koncepcyjnie jako ogólne rabaty.
Klasa „zamówienie tego klienta” prawdopodobnie wymaga kolekcji rabatów. Lista? Haszysz? Połączona lista? Jeszcze mnie to nie obchodzi. Rabaty dotyczą zakupu, a nie klienta!
Zachowaj oddzielne budowanie instancji Rabatu od klienta, koszyka, historii itp. To się bardzo zmieni - jak zauważył @jfrankcarr.
Prawdopodobnie inna klasa dla każdego rabatu, ponieważ algorytm i parametry dla każdego rabatu różnią się gwałtownie i nieprzewidywalnie.
Widzę dużo obsługi zdarzeń, ponieważ obliczanie rabatów reaguje na zmiany w koszyku i na odwrót.
Zastosowanie wzorca projektowego
strategy pattern
. IDiscount to interfejs do implementacji różnych algorytmów rabatowych.Widzę
factory
. Na pewno nie w pełni rozwiniętaabstract factory pattern
, ale jedna klasa w tym momencie analizy. Rozsądnie musi istnieć jedno miejsce, w którym istnieje wystarczający kontekst, aby zdecydować, które rabaty mają zastosowanie, a następnie je utworzyć. Jedna klasa. Jeśli zasady stosowania rabatów później eksplodują z powodu imprezy z grzybami z Działu Marketingu, jakakolwiek dodatkowa logika Konstrukcji Zniżek musi nadal być spójna w tej podstawowej klasie fabryki.Widzę
Chain of Responsibility
. Nie wyklucza to wzajemnie tegofactory
pomysłu. Zamiast iteracji kolekcji rabatów, każda zniżka dzwoni do następnego faceta. Klasa „zamówienie klienta” w tym przypadku nie zawiera kolekcji rabatów.Myślę, że czynnikiem „hmmmm ....” w łańcuchu odpowiedzialności jest to, że każda zniżka ma odniesienie do następnego. Oznacza to, że porządek ma znaczenie. Co nie jest prawdą. Ponadto koncepcja, którą ucieleśnia KR, polega na tym, że jeden obiekt nie może obsłużyć żądania, więc jest ono przekazywane „do następnego wyższego organu”. Nasz model jest inny. Jedynym żądaniem jest obliczenie. Każda zniżka to robi. Wynik lub efekt może być zerowy, ale każdy rabat jest obliczany. Instynktownie skłaniam się ku wyższej wierności w świecie rzeczywistym.
Założenia
Jakie zmiany, co pozostaje bez zmian?
Zniżki są bardzo różne. Inna liczba i rodzaj parametrów, z których składa się każda reguła.
Argumenty za kwalifikującymi się rabatami zmieniają się wraz ze zmianą koszyka.
Zmienia się liczba dostępnych rabatów
Zniżki, które klient kwalifikuje się do zmian wraz ze zmianą koszyka.
Historia zakupów nie zmienia się w kontekście tego zakupu
Całkowity koszt zmienia się dynamicznie w zależności od zastosowanych linii zakupowych i rabatów.
Po początkowym zastosowaniu wynik rabatu może ulec zmianie, na przykład zmienia się ilość zakupu.
źródło
Logicznie rzecz biorąc, model rabatu może być dowolny , więc nie można zakładać, że można zaprogramować wszystkie sprawy z wyprzedzeniem. Nikt, kto odpowie na twoje pytanie, nie może być całkowicie pewien, czego naprawdę potrzebujesz. Zakładając jednak, że otrzymujesz zwykłe rabaty w prawdziwym świecie ...
Ważnym pytaniem jest, czy rabaty zostaną zaprogramowane, czy też chcesz, aby użytkownicy je wprowadzali. Jak wspomniano powyżej, nigdy nie można ich zaprogramować, ale zazwyczaj celem jest próba wprowadzenia większej ilości danych, tak jak w przypadku typowych przypadków, zamiast programowania ich wszystkich. Dotyczy to do pewnego stopnia, nawet jeśli programiści są wykorzystywani do tworzenia wszystkich rabatów.
Martin Fowler wspomina o „metodzie wystąpienia indywidualnego” w „Wzorcach analizy: modele obiektów wielokrotnego użytku” jako część sposobu wdrażania „Reguł księgowania” dla systemów księgowych, ale reguły wydają się dość podobne do twoich. Podałbym więcej szczegółów, ale jest to dzieło chronione prawem autorskim i
W przypadku interfejsu użytkownika musisz albo wymyślić dość proste przypadki użycia, albo zbudować interpreter i narzędzie do tworzenia zapytań. Możliwe, że jedno i drugie dla prostych przypadków i jedno bardziej zaawansowane. Jeśli piszesz interpreter, jest to prawdopodobnie dość dobry przypadek użycia wzorca interpretera, ponieważ kod jest stosunkowo prosty w porównaniu do generatora analizatora składni, a wolniejszy czas analizy prawdopodobnie nie będzie miał znaczenia. (Jeśli lubisz korzystać z generatorów analizatorów składni, nie pozwól mi Cię zatrzymać).
Nie próbuj jednak robić wszystkiego z tłumaczem - w pewnym momencie programujesz po prostu w swoim kiepskim języku, więc równie dobrze możesz użyć prawdziwego. Jeśli Twój interpretowany język obsługuje funkcje (prawdopodobnie powinien obsługiwać ich wywoływanie - definiowanie ich jest wątpliwe), można je zakodować w prawdziwym języku. Nie idź dalej, niż musisz.
Bez względu na to, co robisz, ostatecznie ktoś będzie chciał, aby rabat był oparty na tym, czy kupił w ciągu 30 dni roboczych od promocji - gdzie dni robocze liczą się tylko wtedy, gdy w regionie nie ma wakacji określonych przez kod pocztowy sklepu lub kod klienta kod pocztowy. Nie próbuj więc z góry projektować idealnego systemu - załóż, że czasami będziesz musiał napisać kod dla nowych rodzajów rabatów i odpowiednio zaprojektować.
źródło
Czy ma sens pytanie, czy istnieje przydatny wzorzec tego? Jaki typ wzoru jest wymagany - strukturalny czy behawioralny?
Idealnie, gdybym miał do tego napisać oprogramowanie, wystarczy algorytm . Prosta funkcja, która oblicza całkowity rabat w następujący sposób:
Nie potrzebujesz niczego więcej niż to!
Wyjaśniając: Rozumiem, że będzie wiele reguł - najbardziej podstawowa z takich reprezentacji powinna być w formie zbioru reguł (zestaw atrybutów danych i wynikająca z tego zniżka), a funkcja taka jak powyżej iterowałaby ją do obliczenia. Jeśli reguły zostaną dodane lub usunięte, nie powinieneś zmieniać kodu - po prostu zmień podstawę reguły.
Wzorzec będzie wymagany tylko wtedy, gdy potrzebujemy różnych obiektów, aby uzyskać dostęp do interfejsów API lub komunikować się w celu wykonania zadania.
PS: Pomyśl o tym - kiedy zapora przetwarza pakiety i przepuszcza lub odrzuca pakiety (lub je modyfikuje) - jakiego wzorca używa? Odpowiedź NIE jest z wyżej opisanych!
źródło