Pred kratkim sem iz operacijskega sistema Windows prešel na Mac OS X in nad rezultati sem navdušen. Ampak spet sem preživel le kratko petletno delo na Windows NT in XP; pred tem sem bil 15 let strogo razvijalec Unixa, večinoma na strojih Sun Microsystems. Imel sem tudi srečo, da sem razvil programsko opremo pod Nextstepom, bujnim predhodnikom Unixa na Mac OS X, zato sem malo pristranski.
Poleg čudovitega uporabniškega vmesnika Aqua je Mac OS X Unix, verjetno najboljši obstoječi operacijski sistem. Unix ima veliko zanimivih funkcij; eden najbolj znanih je cev, ki vam omogoča ustvarjanje kombinacij ukazov tako, da izhod enega ukaza povežete z vhodom drugega. Denimo, da želite navesti izvorne datoteke iz izvorne distribucije Struts, ki prikličejo ali definirajo imenovano metodo izvrši ()
. Tukaj je en način, kako to narediti s cevjo:
grep "execute (" `poišči $ STRUTS_SRC_DIR -ime" * .java "` | awk -F: '{print}'
The grep
ukaz išče datoteke v regularnih izrazih; tukaj ga uporabljam za iskanje pojavitev niza izvrši (
v datotekah, ki jih je odkril najti
ukaz. grep
izhod je v cevi awk
, ki v vsako vrstico natisne prvi žeton - ločen s dvopičjem grep
izhod (navpična vrstica pomeni cev). Ta žeton je ime datoteke, zato na koncu dobim seznam imen datotek, ki vsebujejo niz izvrši (
.
Zdaj, ko imam seznam imen datotek, lahko za razvrščanje seznama uporabim drugo cev:
grep "execute (" `poišči $ STRUTS_SRC_DIR -ime" * .java "` | awk -F: '{print}' | razvrsti
Tokrat sem sestavil seznam imen datotek razvrsti
. Kaj pa, če želite vedeti, koliko datotek vsebuje niz izvrši (
? Z drugo cevjo je enostavno:
grep "execute (" `poišči $ STRUTS_SRC_DIR -ime" * .java "` | awk -F: '{print}' | sort -u | wc -l
The stranišče
ukaz šteje besede, vrstice in bajte. V tem primeru sem navedel -l
možnost štetja vrstic, ena vrstica za vsako datoteko. Dodal sem tudi a -u
možnost razvrsti
za zagotovitev edinstvenosti za vsako ime datoteke ( -u
možnost filtrira dvojnike).
Cevi so zmogljive, saj vam omogočajo dinamično sestavljanje verige operacij. Programski sistemi pogosto uporabljajo ekvivalent cevi (npr. E-poštni filtri ali nabor filtrov za strežniški programček). V središču cevi in filtrov je oblikovalski vzorec: Veriga odgovornosti (OR).
Opomba: Izvorno kodo tega članka lahko prenesete iz virov.
Uvod OR
Vzorec verige odgovornosti uporablja verigo predmetov za obdelavo zahteve, ki je običajno dogodek. Predmeti v verigi posredujejo zahtevo po verigi, dokler eden od predmetov ne obravnava dogodka. Obdelava se ustavi po obdelavi dogodka.
Slika 1 prikazuje, kako vzorec OR obdeluje zahteve.
V Vzorci oblikovanja, avtorji opisujejo vzorec verige odgovornosti tako:
Izogibajte se povezovanju pošiljatelja zahteve s sprejemnikom, saj da več predmetom priložnost, da obravnavajo zahtevo. Verižite sprejemne predmete in prošnjo pošljite po verigi, dokler je predmet ne obravnava.Vzorec verige odgovornosti se uporablja, če:
- Ločiti želite pošiljatelja in prejemnika zahteve
- Za obdelavo zahteve je več predmetov, določenih med izvajanjem
- V svoji kodi ne želite izrecno navajati upravljavcev
Če uporabljate vzorec OR, ne pozabite:
- Samo en predmet v verigi obravnava zahtevo
- Nekatere zahteve morda ne bodo obdelane
Te omejitve seveda veljajo za klasično izvajanje OR. V praksi se ta pravila upogibajo; na primer, filtri servlet so izvedba CoR, ki več filtrom omogoča obdelavo zahteve HTTP.
Slika 2 prikazuje diagram razreda vzorcev OR.
Običajno so obdelovalci zahtev razširitve osnovnega razreda, ki ohranja referenco na naslednjega obdelovalca v verigi, znan kot naslednik
. Osnovni razred se lahko izvaja handleRequest ()
Všečkaj to:
javni abstraktni razred HandlerBase {... public void handleRequest (SomeRequestObject sro) {if (naslednik! = null) naslednik.handleRequest (sro); }}
Torej privzeto upravljavci posredujejo zahtevo naslednjemu obdelovalcu v verigi. Konkreten podaljšek HandlerBase
lahko izgleda takole:
javni razred SpamFilter razširja HandlerBase {public void handleRequest (SomeRequestObject mailMessage) {if (isSpam (mailMessage)) {// Če je sporočilo vsiljena pošta, / ukrepajte v zvezi z neželeno pošto. Ne posreduj sporočila. } else {// Sporočilo ni vsiljena pošta. super.handleRequest (mailMessage); // Pošlji sporočilo naslednjemu filtru v verigi. }}}
The SpamFilter
obravnava zahtevo (verjetno prejem novega e-poštnega sporočila), če je sporočilo neželena, zato zahteva ne gre več; v nasprotnem primeru se zaupanja vredna sporočila posredujejo naslednjemu obdelovalcu, verjetno drugemu e-poštnemu filtru, ki jih želi odstraniti. Sčasoma lahko zadnji filter v verigi shrani sporočilo po prehodu skozi več filtrov.
Upoštevajte, da se zgoraj obravnavani hipotetični e-poštni filtri medsebojno izključujejo: Na koncu samo en filter obravnava zahtevo. Lahko se odločite, da to obrnete navzven, tako da več filtrov obdelate eno samo zahtevo, kar je boljša analogija s cevmi Unix. Kakor koli že, osnovni motor je vzorec OR.
V tem članku obravnavam dve izvedbi vzorcev verige odgovornosti: filtre servlet, priljubljeno izvedbo OR, ki omogoča obdelavo zahteve več filtrom, in izvirni model dogodkov AWT (Abstract Window Toolkit), nepriljubljeno klasično izvajanje OR, ki je bilo na koncu zastarelo .
Filtri za servlet
V zgodnjih dneh Java 2 Platform, Enterprise Edition (J2EE) so nekateri vsebniki strežniških programčkov ponujali priročno funkcijo, imenovano veriženje servletov, pri čemer je bilo mogoče v bistvu uporabiti seznam filtrov. Filtri za strežniške programčke so priljubljeni, ker so uporabni za varnost, stiskanje, beleženje in drugo. In seveda lahko sestavite verigo filtrov, da lahko nekatere ali vse te stvari opravite, odvisno od pogonskih pogojev.
S pojavom Java Servlet Specification različice 2.3 so filtri postali standardne komponente. Za razliko od klasičnega CoR filtri servlet omogočajo več predmetov (filtrov) v verigi, da obravnavajo zahtevo.
Servlet filtri so močan dodatek k J2EE. S stališča oblikovalskih vzorcev ponujajo tudi zanimiv preobrat: če želite spremeniti zahtevo ali odgovor, poleg OR uporabite še vzorec okrasja. Slika 3 prikazuje delovanje filtrov strežniškega programčka.
Preprost filter za strežniški programček
Za filtriranje strežniškega programčka morate narediti tri stvari:
- Izvedite strežniški programček
- Uporabite filter
- Povežite filter in strežniški programček
Primeri 1-3 izvedejo vse tri zaporedne korake:
Primer 1. Servlet
uvoz java.io.PrintWriter; uvoz javax.servlet. *; uvoz javax.servlet.http. *; javni razred FilteredServlet razširja HttpServlet {public void doGet (zahteva HttpServletRequest, odgovor HttpServletResponse) vrže ServletException, java.io.IOException {PrintWriter out = response.getWriter (); out.println ("Priklican filtriran programček"); }}
Primer 2. Filter
uvoz java.io.PrintWriter; uvoz javax.servlet. *; uvoz javax.servlet.http.HttpServletRequest; javni razred AuditFilter izvaja Filter {private ServletContext app = null; javna void init (FilterConfig config) {app = config.getServletContext (); } javna praznina doFilter(Zahteva za ServletRequest, odgovor ServletResponse, veriga FilterChain) vrže java.io.IOException, javax.servlet.ServletException {app.log ((((HttpServletRequest) zahteva) .getServletPath ()); veriga.doFilter(zahteva, odgovor); } javna void uniči () {}}
Primer 3. Deskriptor razmestitve
auditFilter AuditFilter <preslikava filtrov>auditFilter/ filteredServlet</ preslikava filtrov> filteredServlet FilteredServlet filteredServlet / filteredServlet ...
Če do strežniškega programčka dostopate z URL-jem / filteredServlet
, auditFilter
dobi razpoko na zahtevo pred strežnikom. AuditFilter.doFilter
piše v datoteko dnevnika vsebnika strežniškega programčka in kliče chain.doFilter ()
za posredovanje zahteve. Za klicanje filtrov strežniškega programčka ni treba chain.doFilter ()
; v nasprotnem primeru se zahteva ne posreduje. Lahko dodam več filtrov, ki bi jih priklicali v vrstnem redu, kot so navedeni v prejšnji datoteki XML.
Zdaj, ko ste videli preprost filter, si oglejmo še en filter, ki spreminja odziv HTTP.
Odziv filtrirajte z vzorcem okrasja
V nasprotju s prejšnjim filtrom morajo nekateri filtri programčkov spremeniti zahtevo ali odgovor HTTP. Zanimivo je, da ta naloga vključuje vzorec dekoraterja. O vzorcu okrasja sem razpravljal v prejšnjih dveh Vzorci Java oblikovanja članka: "Presenetite svoje prijatelje razvijalce z vzorci oblikovanja" in "Okrasite svojo kodo Java."
Primer 4 navaja filter, ki v telesu odziva izvede preprosto iskanje in zamenjavo. Ta filter okrasi odziv servleta in ga posreduje servletu. Ko strežniški programček konča pisanje v okrašeni odziv, filter izvede iskanje in zamenjavo v vsebini odziva.
Primer 4. Filter za iskanje in zamenjavo
uvoz java.io. *; uvoz javax.servlet. *; uvoz javax.servlet.http. *; javni razred SearchAndReplaceFilter izvaja Filter {private FilterConfig config; javna void init (FilterConfig config) {this.config = config; } javni FilterConfig getFilterConfig () {return config; } public void doFilter (zahteva za ServletRequest, odgovor ServletResponse, veriga FilterChain) vrže java.io.IOException, javax.servlet.ServletException {StringWrapper ovoj = nov StringWrapper((HttpServletResponse) odgovor); veriga.doFilter(prošnja, ovoj); String responseString = wrapper.toString(); String search = config.getInitParameter ("iskanje"); String replace = config.getInitParameter ("replace"); if (search == null || replace == null) return; // Parametri niso pravilno nastavljeni int index = responseString.indexOf (iskanje); if (index! = -1) {String beforeReplace = responseString.substring (0, indeks); String afterReplace = responseString.substring (index + search.length ()); response.getWriter (). print(beforeReplace + replace + afterReplace); }} javna void uniči () {config = null; }}
Prejšnji filter išče imenovane parametre init filtra Iskanje
in zamenjati
; če so definirani, filter nadomesti prvo pojavitev Iskanje
vrednost parametra z zamenjati
vrednost parametra.
SearchAndReplaceFilter.doFilter ()
zavije (ali okrasi) odzivni predmet z ovojem (okrasnikom), ki je namesto odgovora. Kdaj SearchAndReplaceFilter.doFilter ()
klici chain.doFilter ()
za posredovanje zahteve posreduje ovoj namesto prvotnega odgovora. Zahteva se posreduje strežniku, ki ustvari odgovor.
Kdaj chain.doFilter ()
vrne se strežniški programček opravi z zahtevo, zato grem v službo. Najprej preverim Iskanje
in zamenjati
parametri filtra; če je prisoten, dobim niz, povezan z ovitkom odziva, to je vsebina odziva. Nato naredim zamenjavo in jo natisnem nazaj v odgovor.
Primer 5 navaja StringWrapper
razred.
Primer 5. Dekorater
uvoz java.io. *; uvoz javax.servlet. *; uvoz javax.servlet.http. *; javni razred StringWrapper razširja HttpServletResponseWrapper {StringWriter Writer = new StringWriter (); javni StringWrapper (HttpServletResponse odgovor) {super (odgovor); } public PrintWriter getWriter () {vrni novo PrintWriter (zapisovalnik); } javni String toString () {return writer.toString (); }}
StringWrapper
, ki okrasi odziv HTTP v primeru 4, je razširitev HttpServletResponseWrapper
, ki nam prizanaša z napornim ustvarjanjem osnovnega razreda dekoraterja za okrasitev odzivov HTTP. HttpServletResponseWrapper
na koncu izvaja ServletResponse
vmesnik, torej primeri HttpServletResponseWrapper
se lahko prenese na katero koli metodo, ki pričakuje a ServletResponse
predmet. Zato SearchAndReplaceFilter.doFilter ()
lahko pokličete chain.doFilter (zahteva, ovoj)
namesto chain.doFilter (zahteva, odziv)
.
Zdaj, ko imamo filter in ovoj za odzive, povežemo filter z vzorcem URL-ja in določimo vzorce iskanja in zamenjave: