Programiranje

Svojim programom, ki temeljijo na Spring, dodajte preprost mehanizem pravil

Vsak netrivialni projektni program vsebuje netrivialno količino tako imenovane poslovne logike. Kaj točno predstavlja poslovno logiko, je diskutabilno. V gorah kode, izdelane za tipično programsko aplikacijo, koščki tu in tam dejansko opravijo tisto delo, za katero je bila zahtevana programska oprema - obdelujejo naročila, nadzorujejo orožne sisteme, rišejo slike itd. , beleženje, transakcije, jezikovne nenavadnosti, okviri in druge poteze sodobne poslovne aplikacije.

Pogosto se poslovna logika globoko prepleta z vsemi ostalimi deli. Ko se uporabijo težki, vsiljivi okviri (kot je Enterprise JavaBeans), je še posebej težko ugotoviti, kje se konča poslovna logika in začne koda, ki temelji na okolju.

V dokumentih o opredelitvi zahtev je le redko navedena ena zahteva glede programske opreme, vendar ima moč izdelati ali prekiniti kateri koli projekt programske opreme: prilagodljivost, merilo, kako enostavno je spremeniti programsko opremo kot odziv na spremembe poslovnega okolja.

Sodobna podjetja so prisiljena biti hitra in prilagodljiva in enako želijo tudi od svoje poslovne programske opreme. Poslovna pravila, ki so bila danes tako skrbno uvedena v poslovno logiko vaših predavanj, bodo jutri zastarela in jih bo treba hitro in natančno spremeniti. Ko ima vaša koda poslovno logiko zakopano globoko v tone in tone tistih drugih bitov, bo sprememba hitro postala počasna, boleča in nagnjena k napakam.

Ni čudno, da so danes nekatera najmodernejša področja v programski opremi za podjetja pravila upravljanja in različni sistemi za upravljanje poslovnih procesov (BPM). Ko pogledate marketinški govor, ta orodja obljubljajo v bistvu isto: Sveti gral poslovne logike, zajet v odlagališču, čisto ločen in samostojen, pripravljen na klic iz katere koli aplikacije, ki jo imate v svoji programski hiši.

Čeprav imajo motorji s komercialnimi pravili in sistemi BPM številne prednosti, vključujejo tudi številne pomanjkljivosti. Najlažje je izbrati ceno, ki lahko včasih zlahka doseže sedemmestne številke. Druga težava je pomanjkanje praktične standardizacije, ki se nadaljuje še danes, kljub velikim prizadevanjem industrije in številnim standardom na papirju. In ker se vedno več trgovin s programsko opremo prilagaja agilnim, vitkim in hitrim razvojnim metodologijam, se ta težka orodja težko prilegajo.

V tem članku zgradimo preprost mehanizem pravil, ki na eni strani izkorišča jasno ločitev poslovne logike, značilne za takšne sisteme, na drugi strani pa, ker je v priljubljenem in zmogljivem okviru J2EE podprt s podporo, ne trpijo zaradi zapletenosti in "nehladnosti" komercialnih ponudb.

Pomladni čas v vesolju J2EE

Potem ko je zapletenost poslovne programske opreme postala nevzdržna in se je v središču pozornosti pojavil problem poslovne logike, se je rodil Spring Framework in podobni. Verjetno je Spring najboljša stvar, ki se je podjetniški Javi zgodila že dolgo. Spring ponuja dolg seznam orodij in majhnih priročnih kod, ki naredijo programiranje J2EE bolj objektno usmerjeno, veliko lažje in bolj zabavno.

V osrčju Pomladi leži načelo Inverzije nadzora. To je modno in preobremenjeno ime, vendar gre za te preproste ideje:

  • Funkcionalnost vaše kode je razdeljena na majhne obvladljive koščke
  • Ti deli so predstavljeni s preprostimi, standardnimi fižoli Java (preprosti razredi Java, ki kažejo nekatere, vendar ne vse, specifikacije JavaBeans)
  • Ti veš ne vključite se v upravljanje teh zrn (ustvarjanje, uničevanje, nastavljanje odvisnosti)
  • Namesto tega posoda Spring to stori namesto vas na podlagi nekaterih opredelitev konteksta običajno na voljo v obliki datoteke XML

Spring ponuja tudi številne druge funkcije, kot so popoln in zmogljiv okvir Model-View-Controller za spletne aplikacije, priročni ovitki za programiranje Java Database Connectivity in ducat drugih okvirov. Toda ti predmeti segajo tudi izven obsega tega članka.

Preden opišem, kaj je potrebno za ustvarjanje preprostega mehanizma pravil za aplikacije, ki temeljijo na Springu, razmislimo, zakaj je ta pristop dobra ideja.

Zasnove upravljalnih motorjev imajo dve zanimivi lastnosti, zaradi katerih sta vredni:

  • Najprej ločujejo kodo poslovne logike od drugih področij aplikacije
  • Drugič, so zunanje nastavljive, kar pomeni, da se definicije poslovnih pravil ter kako in v kakšnem vrstnem redu sprožijo hranijo zunaj aplikacije in z njimi upravlja ustvarjalec pravil, ne uporabnik aplikacije ali celo programer

Vzmet je primerna za pravilen motor. Visokokomponentna zasnova pravilno kodirane aplikacije Spring spodbuja umestitev vaše kode v majhne, ​​obvladljive, ločeno kosov (fižol), ki jih je mogoče zunanje konfigurirati s pomočjo definicij konteksta Spring.

Preberite v nadaljevanju, da raziščete to dobro ujemanje med tem, kar potrebuje zasnova motorja s pravilom, in tem, kar že ponuja zasnova Spring.

Zasnova vzmetnega mehanizma pravil

Naš načrt temelji na interakciji pomladno nadzorovanih zrn Java, ki jih imenujemo pravilo sestavni deli motorja. Določimo dve vrsti komponent, ki bi jih morda potrebovali:

  • An ukrepanje je komponenta, ki v naši aplikacijski logiki dejansko naredi nekaj koristnega
  • A pravilo je komponenta, ki omogoča odločitev v logičnem toku dejanj

Ker smo veliki ljubitelji dobrega objektno usmerjenega oblikovanja, naslednji osnovni razred zajema osnovno funkcionalnost vseh prihodnjih komponent, in sicer zmožnost, da jih druge komponente z nekim argumentom pokličejo:

javni abstraktni razred AbstractComponent {javna abstraktna void izvedba (Object arg) vrže izjemo; }

Osnovni razred je seveda abstrakten, ker ga nikoli ne bomo potrebovali samega.

In zdaj, koda za AbstractAction, ki naj se razširi z drugimi prihodnjimi konkretnimi ukrepi:

javni abstraktni razred AbstractAction razširja AbstractComponent {

zasebno AbstractComponent nextStep; javno izvajanje void (Object arg) vrže izjemo {this.doExecute (arg); if (nextStep! = null) nextStep.execute (arg); } zaščitena abstraktna void doExecute (Object arg) vrže izjemo;

javna praznina setNextStep (AbstractComponent nextStep) {this.nextStep = nextStep; }

public AbstractComponent getNextStep () {return nextStep; }

}

Kot lahko vidite, AbstractAction naredi dve stvari: shrani definicijo naslednje komponente, ki jo prikliče naš mehanizem pravil. In v svojem izvrši () metoda pokliče a doExecute () metoda, ki jo je treba opredeliti s konkretnim podrazredom. Po doExecute () vrne se naslednja komponenta, če ta obstaja.

Naše PovzetekRule je podobno preprosto:

javni abstraktni razred AbstractRule razširja AbstractComponent {

zasebno AbstractComponent positiveOutcomeStep; zasebno AbstractComponent negativeOutcomeStep; javno izvajanje void (Object arg) vrže izjemo {boolean result = makeDecision (arg); if (result) positiveOutcomeStep.execute (arg); else negativeOutcomeStep.execute (arg);

}

zaščitena abstraktna logična makeDecision (Object arg) vrže izjemo;

// Getterji in nastavitelji za positiveOutcomeStep in negativeOutcomeStep so zaradi kratkosti izpuščeni

V svojem izvrši () metoda, AbstractAction pokliče odloči se() metoda, ki jo izvede podrazred, nato pa, odvisno od rezultata te metode, pokliče eno od komponent, ki je opredeljena kot pozitiven ali negativen rezultat.

Ko to predstavimo, je naša zasnova popolna SpringRuleEngine razred:

javni razred SpringRuleEngine {private AbstractComponent firstStep; javna praznina setFirstStep (AbstractComponent firstStep) {this.firstStep = firstStep; } public void processRequest (Object arg) vrže izjemo {firstStep.execute (arg); }}

To je vse, kar je v glavnem razredu našega mehanizma pravil: definicija prve komponente v naši poslovni logiki in metoda za začetek obdelave.

Toda počakajte, kje je vodovod, ki povezuje vse naše razrede, da lahko delujejo? Nato boste videli, kako nam čarovnija Pomladi pomaga pri tej nalogi.

Vzmetni mehanizem pravil v akciji

Oglejmo si konkreten primer, kako bi lahko ta okvir deloval. Upoštevajte ta primer uporabe: razviti moramo aplikacijo, odgovorno za obdelavo vlog za posojilo. Izpolniti moramo naslednje zahteve:

  • Prijavo preverimo za popolnost in jo sicer zavrnemo
  • Preverimo, ali je prošnjo vložil vlagatelj, ki živi v državi, kjer imamo pooblastilo za poslovanje
  • Preverjamo, ali mesečni dohodek prosilca in njegovi mesečni stroški ustrezajo razmerju, v katerem se počutimo dobro
  • Dohodne aplikacije se shranijo v zbirko podatkov prek storitve trajnosti, o kateri ne vemo ničesar, razen njenega vmesnika (morda je bil njegov razvoj oddan v Indijo)
  • Poslovna pravila se lahko spremenijo, zato je potrebna zasnova mehanizma pravil

Najprej oblikujmo razred, ki predstavlja našo prošnjo za posojilo:

javni razred LoanApplication {public static final String INVALID_STATE = "Žal ne poslujemo v vaši državi"; public static final String INVALID_INCOME_EXPENSE_RATIO = "Žal posojila ne moremo zagotoviti glede na to razmerje med stroški in prihodki"; public static final String APPROVED = "Vaša prijava je odobrena"; public static final String INSUFFICIENT_DATA = "Niste navedli dovolj informacij o svoji prijavi"; javni statični končni niz INPROGRESS = "v teku"; javni statični končni niz [] STATUSI = nov niz [] {INSUFFICIENT_DATA, INVALID_INCOME_EXPENSE_RATIO, INVALID_STATE, APPROVED, INPROGRESS};

private String firstName; zasebni niz lastName; zasebni dvojni dohodek; zasebni dvojni izdatki; private String stateCode; status zasebnega niza; javna void setStatus (status niza) {if (! Arrays.asList (STATUSI) .contains (status)) vrže novo IllegalArgumentException ("neveljaven status:" + status); this.status = status; }

// Skupina drugih pridobivalcev in nastaviteljev je izpuščena

}

Naše storitve vztrajnosti opisuje naslednji vmesnik:

javni vmesnik LoanApplicationPersistenceInterface {public void recordApproval (aplikacija LoanApplication) vrže izjemo; public void recordRejection (aplikacija LoanApplication) vrže izjemo; public void recordIncomplete (aplikacija LoanApplication) vrže izjemo; }

Temu vmesniku se hitro posmehujemo z razvojem a MockLoanApplicationPersistence razred, ki ne izpolnjuje nič drugega kot izpolnjuje pogodbo, določeno z vmesnikom.

Uporabljamo naslednji podrazred SpringRuleEngine razred za nalaganje pomladnega konteksta iz datoteke XML in dejansko začetek obdelave:

javni razred LoanProcessRuleEngine razširja SpringRuleEngine {javni statični SpringRuleEngine getEngine (ime niza) {ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext ("SpringRuleEngineContext.xml"); return (SpringRuleEngine) context.getBean (ime); }}

V tem trenutku imamo okostje na mestu, zato je pravi čas, da napišemo test JUnit, ki je prikazan spodaj. Izhaja nekaj predpostavk: Pričakujemo, da bo naše podjetje delovalo le v dveh zveznih državah, Teksasu in Michiganu. In posojila sprejemamo samo z razmerjem med odhodki in prihodki 70 odstotkov ali več.

javni razred SpringRuleEngineTest razširja TestCase {

public void testSuccessfulFlow () vrže izjemo {SpringRuleEngine engine = LoanProcessRuleEngine.getEngine ("SharkysExpressLoansApplicationProcessor"); LoanApplication aplikacija = nova LoanApplication (); application.setFirstName ("Janez"); application.setLastName ("Doe"); application.setStateCode ("TX"); application.setExpences (4500); application.setIncome (7000); engine.processRequest (aplikacija); assertEquals (LoanApplication.APPROVED, application.getStatus ()); } public void testInvalidState () vrže izjemo {SpringRuleEngine engine = LoanProcessRuleEngine.getEngine ("SharkysExpressLoansApplicationProcessor"); LoanApplication aplikacija = nova LoanApplication (); application.setFirstName ("John"); application.setLastName ("Doe"); application.setStateCode ("V redu"); application.setExpences (4500); application.setIncome (7000); engine.processRequest (aplikacija); assertEquals (LoanApplication.INVALID_STATE, application.getStatus ()); } public void testInvalidRatio () vrže izjemo {SpringRuleEngine engine = LoanProcessRuleEngine.getEngine ("SharkysExpressLoansApplicationProcessor"); LoanApplication aplikacija = nova LoanApplication (); application.setFirstName ("John"); application.setLastName ("Doe"); application.setStateCode ("MI"); application.setIncome (7000); application.setExpences (0,80 * 7000); // previsok motor.processRequest (aplikacija); assertEquals (LoanApplication.INVALID_INCOME_EXPENSE_RATIO, application.getStatus ()); } public void testIncompleteApplication () vrže izjemo {SpringRuleEngine engine = LoanProcessRuleEngine.getEngine ("SharkysExpressLoansApplicationProcessor"); LoanApplication aplikacija = nova LoanApplication (); engine.processRequest (aplikacija); assertEquals (LoanApplication.INSUFFICIENT_DATA, application.getStatus ()); }

$config[zx-auto] not found$config[zx-overlay] not found