Jaki pattern użyć do wieloetapowego zadania?

0

pisze logikę w której jest jakis proces i ma on pare etapów:

  1. najpierw zrob to
  2. potem zrob tamto
  3. itd..

chcialbym osiągnąc taki efekt, że jeśli jeden z etapów zawiedzie, następne sie nie wykonają (we wszystkich lub w ew. w niektorych z tych etapów)
możecie mi zaproponowac jakis pattern albo podejscie do tego?

próbuje zaadoptować do tego responsibility chain tylko tak srednio to idzie, bo przeszedlem juz przez wiele problemów które jakos-tam rozwiązałem, a na końcu nie osiągnąłem w sumie wiele więcej niż jakbym logikę po kolei wrzucił w jedną metodę i użył paru ifów..
plus tego taki ze mam mniejsze klasy/metody
minus tego taki, ze mam bardzo duzo klas (kazdy etap to osobna klasa, nawet jesli to podobna operacja na bazie typu zmiana wartosci 1 pola, musze zachowac ciało metody w klasie Etap i nie moge przekazac sobie byle-jakiego parametru)

to dobrze mieć dużo, małych, BARDZO konkretną rzecz robiących klas, które uczestnicza we flow jakiegos procesu?
ładnie to wygląda, ale nie wiem czy nie za duzo boilerplatu

1

Wzorzec komendy (command).

0

@margor90 thx, próbuje tu go dopasować do potrzeb i mam z tego powodu pytanie
Zakladajac ze mamy interfejs Command i metode execute():
powiedzcie mi, według was jest w porządku pisanie krótkich, nie "zgeneralizowanych" klas jako implementacji commendy?
Tzn np. CheckUserExistsCommand zamiast ogólnego DatabaseCommand albo SetStatusDoneCommand + SetStatusAvailableCommand zamiast ogólnego SetOrderStatusCommand?

tak defacto uzycie commanda zmieni tyle ze wywolywanie metody execute mam nijako wyjęte na zewnątrz, wiec moglbym lapac np jakis OrderException w wypadku błędu podczas ktoregos z etapów
(btw. jak ktoras command'a sie nie powiedzie to jak jeszcze proponujecie poinformować Clienta o tym ze miala blad?)

0

Do informowania o błędach obserwator.

1

Możesz też użyć maszyny stanów.

0

jak są to operacje na bazie to nie możesz napisać normalnie i po prostu opanować to w transakcję?

0

Nie wciskaj wszędzie wzorców, de facto wzorzec chain of responsibility pasuje (komenda nie pasuje - jej przeznaczenie jest troche inne) do twojego problemu - prawdopodobnie, ale informowanie o błędach w postaci wyjątków niekontrolowanych jest git, do tego one służą.

0

Ale lepiej opisz swój problem, żeby na pewno dobrze dopasować rozwiązanie do problemu

0

Jak napisałem wyżej. Podejście z maszyną stanów mi się podoba.

Nie jestem pewien co do chain of responsibility - przecież jego idea to przepuszczenie żądanie przez poszczegolne ogniwa, aż znajdzie się takie, które je obsłuży. Pozostałe nic nie robią.
Tutaj idealne jest stworzenie stanów, vide: jesteśmy w stanie n, robimy wymagane dla tego stanu operacje -> stan się zmienił na inny.

0

Możesz spróbować work flow, używałem http://www.jbpm.org jest darmowe i dobre.
Pozdro

0

@margor90 nie chodzi mi o to zeby napakowac to wzorcami tylko optymalnie rozwiazac; w za małych przypadkach wzorce czasem daja wiecej boilerplateu niz korzysci

@karolinaa nie moge bo to nie sa tylko operacje na bazie, to podalem jako przyklad bo tez takie etapy istnieją

@Miły adolf wlasnie nie jestem pewien czy chain pasuje, bo to jest afaik wzorzec, gdzie kilka klas obsługuje ten sam typ żądań, ale dla roznych wlasciwosci (np jednen element chain wydaje banknoti 100zł, inny 50, 20 10 itd i kwota do wyplaty np 375zl jest przekazywana przez kolejne etapy chainu)

command wydaje mi sie wzorcem gdzie po prostu mamy kolejne etapy, interfejs ktory reprezentuje abstrakcyjny etap i konkretne implementacje, które klient wywołuje w wybranej kolejnosci

choc moge sie mylic

edit
@xfin
poczytam o maszynie stanow jak bede mial chwile

@margor90
odnosnie komentarza, jak zimplementowalbys w commandzie rollback czyli cos ala transakcje? (cofniecie wszystkich zmian jesli ktorys etap zawiedzie)

0

Dobre rozwiązanie masz wtedy gdy: kod daje się modyfikować bez względnej masakry (zmiana wymagań) i testować. Podręcznikowo wzorców raczej się nie używa to jedynie wskazówki dotyczące powtarzalnych rozwiązań, które się sprawdziły w określonych warunkach. Poza tym często wzorce potrafią stać się antywzorcami np. DTO w określonych warunkach.
Pisząc obserwator miałem na myśli, że jeśli np. Twoja aplikacja ma asynchronicznie powiadamiać o przebiegu workflow to się aż prosi o obserwatora (temat lub kolejka w zależności od ilości odbiorców). Z kolei jak chcesz chamsko przerwać blokującą operację obserwator nie jest najlepszym wyjściem.

W zasadzie jaki jest problem z Twoim obecnym rozwiązaniem skoro poszukujesz następnych wzorców. Źle się testuje, trudno dopisuje się nowe wymagania?

Co do pytania o transakcje, to można to zrobić tak abyś pamiętał stan przed rozpoczęciem polecenia. Mogą być różne implementacje:
https://en.wikipedia.org/wiki/Command_pattern
Tam piszą tak:

Transactional behavior
Similar to undo, a database engine or software installer may keep a list of operations that have been or will be performed. Should one of them fail, all others can be reversed or discarded (usually called rollback). For example, if two database tables that refer to each other must be updated, and the second update fails, the transaction can be rolled back, so that the first table does not now contain an invalid reference.

0

@margor90 pierwotnie rozwiazanie bylo takie ze nie bylo wzorca tylko po prostu metoda ktora wykonywala te etapy po kolei. problem sie pojawil gdy etapow przybylo, kazdy etap uzywal jakiegos serwisu ktory trzeba bylo wstrzyknac, przez co lista pol wzrastala i metoda sie zwiekszala, a etapow ma byc wiecej

okazalo się ze na etapie np wysylania jakiejs wiadomosci jeśli nie powiedzie się ona, to trzeba cofnac zmiany (lub chociaz powiadomic usera ze sie nie wyslala wiadomosc) (dla przykladu: tworzymy aukcje, wiec jest obiekt Auction, po jej zakupie ktos dostaje powiadomienie na np email - jesli wysylanie tego emaila sie nie powiedzie chcialbym zeby zamawiajacy jakos o tym wiedzial albo/i zeby cała aukcja sie cofnela, czyli wciaz byla dostepna do zakupu)

Cały proces ma pare etapów i chyba najlepiej zeby wyglądał tak, że jak coś po drodze się nie uda to user dostanie info co sie stalo i zmiany się cofną. (ew zeby byla mozliwosc wyboru czy cofnac je i zapomniec czy zeby jeszcze raz sprobowac przejsc przez te etapy)

czyli ogolnie jakis pattern ktory w miare elastycznie mozna używać, dopisywac etapy i tak zeby przez te etapy przekazywać obiekty (jak np w etapie dzialania na bazie zweryfikuje czy dana aukcja/user istnieje to zeby w kolejnej fazie móc z tego obiektu wyciagnietego skorzystac i nie robic 2x selecta (ew. jakis cache))

pierwszym pomyslem byl chain of responsibility bo tam moge w danym etapie sprawdzic czy sie udalo to co mialo sie udac, i jesli nie to nie wolac nastepnego etapu, ale problem jest z tym ze klasy musza byc bardzo okreslone (bo metoda ktora wołam np execute() ma okreslone parametry wiec jesli miedzy faza druga a trzecia chce przemiescic jakis obiekt to nie bardzo mam jak), wiec moge troche zabic performance
no i nie zastanawialem sie jeszcze nad rollbackiem w tym podejsciu

boli troche ze jedna metoda na 1X linijek rozchodzi sie na ileś malutkich klas, nie-reużywalnych

0

Może wystarczy templeMetod? Napiszesz klasę bazową z metodą DoSomething i w niej strukturalnie rozwiązać problem tempami,a w klasach dziedziczących nadpisać co trzeba. heh "stany" w sumie wyszły mi nie chcący ale jak juz napisałem to niech zostanie.

DoSomthing(object[] arg)
{
   var stan = sprawdzDanetemple(arg);
   stan = krokATemple(arg,stan);
   stan = krokBTemple(arg,stan);
//...
}
krokATemple(arg,stan)
{
   if(stan == error)
     return error;
//...
}
 

Albo możesz spróbować tak ze wszystkim swoim komendą zaimplementujesz intrefejs np. drewa binarnego lub listy z dowiązaniami, i napiszesz klase która bedzie umiała po tym drzewie chodzić. To też będziesz pewnego rodzaju maszyna stanów ale będziesz mógł tworzyć kolejne stany za pomocą kompozycji a nie dziedziczenia lub ifów. Potrzebujesz dodać dodatkowy krok miedzy sekwencjami dla jakiegoś szczególnego przypadku, piszesz odpalasz DodajKrok(krok, pozycja); i gotowe. Rozwiązuje to też oche trproblem przekazywania zmiennych bo możesz trzymać je w klasie "do przemieszczania".

1 użytkowników online, w tym zalogowanych: 0, gości: 1