Programmēšana

Sekojiet atbildības ķēdei

Nesen no Windows pārgāju uz Mac OS X, un esmu sajūsmā par rezultātiem. Bet atkal es pavadīju tikai īsu piecu gadu laiku operētājsistēmās Windows NT un XP; pirms tam es 15 gadus biju stingri Unix izstrādātājs, galvenokārt Sun Microsystems mašīnās. Man arī paveicās izstrādāt programmatūru Nextstep, sulīgā Unix balstītā Mac OS X priekštecī, tāpēc esmu nedaudz aizspriedumains.

Neskaitot skaisto Aqua lietotāja saskarni, Mac OS X ir Unix, iespējams, labākā pastāvošā operētājsistēma. Unix ir daudz atdzist funkciju; viens no pazīstamākajiem ir caurule, kas ļauj jums izveidot komandu kombinācijas, novirzot vienas komandas izvadi uz citas ievadi. Piemēram, pieņemsim, ka vēlaties uzskaitīt avota failus no avota izplatīšanas Struts, kas izsauc vai definē metodi ar nosaukumu izpildīt(). Šeit ir viens veids, kā to izdarīt ar cauruli:

 grep "execute (" `atrast $ STRUTS_SRC_DIR -name" * .java "" | awk -F: '{print}' 

The grep komanda meklē failos regulāras izteiksmes; šeit es to izmantoju, lai atrastu virknes gadījumus izpildīt( failos, kurus atklāj atrast komandu. grepprodukcija tiek ievadīta awk, kas katrā rindā izdrukā pirmo marķieri, kuru norobežo kols grepizlaide (vertikāla josla apzīmē cauruli). Šis marķieris ir faila nosaukums, tāpēc es izveidoju to failu nosaukumu sarakstu, kuros ir virkne izpildīt(.

Tagad, kad man ir failu nosaukumu saraksts, es varu izmantot citu cauruli, lai kārtotu sarakstu:

 grep "execute (" "atrast $ STRUTS_SRC_DIR -name" * .java "" | awk -F: '{print}' | kārtot

Šoreiz es esmu nosūtījis failu nosaukumu sarakstu kārtot. Ko darīt, ja vēlaties uzzināt, cik failos ir virkne izpildīt(? Ar citu cauruli ir viegli:

 grep "execute (" "atrast $ STRUTS_SRC_DIR -name" * .java "" | awk -F: '{print}' | kārtot -u | wc -l 

The tualete komanda skaita vārdus, rindas un baitus. Šajā gadījumā es norādīju -l iespēja skaitīt rindas, viena rinda katram failam. Es arī pievienoju a -u iespēja kārtot lai nodrošinātu katra faila nosaukuma unikalitāti ( -u filtrē dublikātus).

Caurules ir jaudīgas, jo ļauj dinamiski sastādīt darbību ķēdi. Programmatūras sistēmās bieži tiek izmantots cauruļu ekvivalents (piemēram, e-pasta filtri vai servleta filtru komplekts). Cauruļu un filtru centrā ir dizaina modelis: atbildības ķēde (RK).

Piezīme: Šī raksta avota kodu varat lejupielādēt vietnē Resursi.

RK ievads

Atbildības ķēdes modelis izmanto objektu ķēdi, lai apstrādātu pieprasījumu, kas parasti ir notikums. Ķēdes objekti pārsūta pieprasījumu pa ķēdi, līdz kāds no objektiem apstrādā notikumu. Apstrāde tiek pārtraukta pēc notikuma apstrādes.

1. attēlā parādīts, kā RK modelis apstrādā pieprasījumus.

In Dizaina modeļi, autori atbildības ķēdes modeli raksturo šādi:

Izvairieties saistīt pieprasījuma sūtītāju ar tā uztvērēju, dodot iespēju vairākiem objektiem apstrādāt pieprasījumu. Ķēdējiet saņemošos objektus un nododiet pieprasījumu gar ķēdi, līdz objekts to apstrādā.

Atbildības ķēdes modelis ir piemērojams, ja:

  • Jūs vēlaties atvienot pieprasījuma sūtītāju un saņēmēju
  • Vairāki objekti, kas noteikti izpildlaikā, ir kandidāti, kas apstrādā pieprasījumu
  • Jūs nevēlaties kodā skaidri norādīt apstrādātājus

Ja izmantojat RK modeli, atcerieties:

  • Tikai viens ķēdes objekts apstrādā pieprasījumu
  • Daži pieprasījumi, iespējams, netiks apstrādāti

Šie ierobežojumi, protams, attiecas uz klasisku RK īstenošanu. Praksē šie noteikumi ir saliekti; piemēram, servletu filtri ir RK ieviešana, kas ļauj vairākiem filtriem apstrādāt HTTP pieprasījumu.

2. attēlā parādīta RK modeļa klases diagramma.

Parasti pieprasījumu apstrādātāji ir bāzes klases paplašinājumi, kas saglabā atsauci uz nākamo apstrādātāju ķēdē, kas pazīstams kā pēctecis. Bāzes klase varētu ieviest handRequest () kā šis:

 publiskā abstraktā klase HandlerBase {... public void handleRequest (SomeRequestObject sro) {if (tiesību pārņēmējs! = null) pārņēmējs.handleRequest (sro); }} 

Tātad pēc noklusējuma apstrādātāji nodod pieprasījumu nākamajam ķēdes apstrādātājam. Betona pagarinājums HandlerBase varētu izskatīties šādi:

 public class SpamFilter paplašina HandlerBase {public void handleRequest (SomeRequestObject mailMessage) {if (isSpam (mailMessage)) {// Ja ziņojums ir surogātpasts // veiciet ar surogātpastu saistītas darbības. Nepārsūtīt ziņojumu. } else {// Ziņojums nav mēstule. super.handleRequest (mailMessage); // Nodot ziņojumu nākamajam ķēdes filtram. }}} 

The SpamFilter apstrādā pieprasījumu (domājams, ka saņem jaunu e-pastu), ja ziņojums ir mēstule, un tāpēc pieprasījums netiek tālāk; pretējā gadījumā uzticami ziņojumi tiek nosūtīti nākamajam apstrādātājam, iespējams, vēl vienam e-pasta filtram, kas vēlas tos atsijāt. Galu galā pēdējais filtrs ķēdē, iespējams, glabā ziņojumu pēc tam, kad tas iet garām, pārvietojoties pa vairākiem filtriem.

Ņemiet vērā, ka iepriekš apspriestie hipotētiskie e-pasta filtri ir savstarpēji izslēdzoši: galu galā tikai viens filtrs apstrādā pieprasījumu. Jūs varat izvēlēties to pagriezt uz augšu, ļaujot vairākiem filtriem apstrādāt vienu pieprasījumu, kas ir labāka līdzība ar Unix caurulēm. Jebkurā gadījumā pamatā esošais motors ir RK modelis.

Šajā rakstā es aplūkoju divas atbildības ķēdes modeļa ieviešanas: servletu filtrus, populāru RK ieviešanu, kas ļauj vairākiem filtriem apstrādāt pieprasījumu, un sākotnējo Abstract Window Toolkit (AWT) notikumu modeli - nepopulāru RK klasisko ieviešanu, kas galu galā tika novecojusi .

Servletu filtri

Java 2 Platform, Enterprise Edition (J2EE) agrīnajos laikos daži servletu konteineri nodrošināja ērtu funkciju, kas pazīstama kā servletīklu ķēde, tādējādi servletī būtībā varēja piemērot filtru sarakstu. Serversīklietu filtri ir populāri, jo tie ir noderīgi drošībai, saspiešanai, reģistrēšanai un citur. Un, protams, jūs varat sastādīt filtru ķēdi, lai veiktu dažas vai visas šīs darbības atkarībā no izpildlaika apstākļiem.

Ar Java Servlet specifikācijas 2.3 versijas parādīšanos filtri kļuva par standarta komponentiem. Atšķirībā no klasiskā RK servleta filtri ļauj vairākiem ķēdes objektiem (filtriem) apstrādāt pieprasījumu.

Servletu filtri ir spēcīgs papildinājums J2EE. Arī no dizaina modeļu viedokļa tie nodrošina interesantu vērpjot: Ja vēlaties modificēt pieprasījumu vai atbildi, papildus RK izmantojat arī dekoratoru. 3. attēlā parādīts, kā darbojas servletu filtri.

Vienkāršs servleta filtrs

Lai filtrētu serveri, jums jādara trīs lietas:

  • Ievietojiet servletu
  • Ievietojiet filtru
  • Saistiet filtru un servletu

1.-3. Piemērs veic visas trīs darbības pēc kārtas:

1. piemērs. Servlets

importēt java.io.PrintWriter; importēt javax.servlet. *; importēt javax.servlet.http. *; public class FilteredServlet paplašina HttpServlet {public void doGet (HttpServletRequest pieprasījums, HttpServletResponse atbilde) izmet ServletException, java.io.IOException {PrintWriter out = response.getWriter (); out.println ("izsaukta filtrēta servetkopa"); }} 

2. piemērs. Filtrs

importēt java.io.PrintWriter; importēt javax.servlet. *; importēt javax.servlet.http.HttpServletRequest; publiskā klase AuditFilter ievieš filtru {private ServletContext app = null; public void init (FilterConfig config) {app = config.getServletContext (); } public void doFilter(ServletRequest pieprasījums, ServletResponse atbilde, FilterChain ķēde) izmet java.io.IOException, javax.servlet.ServletException {app.log ((((HttpServletRequest) pieprasījums) .getServletPath ()); chain.doFilter(pieprasījums, atbilde); } public void iznīcināt () {}} 

3. piemērs. Izvietošanas deskriptors

    auditFilter AuditFilter <filtru kartēšana>auditFilter/ filteredServlet</ filtrēšanas kartēšana> filteredServlet FilteredServlet filteredServlet / filteredServlet ... 

Ja piekļūstat servletam ar URL / filteredServlet, auditFilter pēc servleta pieprasījuma saņem plaisu. AuditFilter.doFilter raksta servleta konteinera žurnāla failā un zvana chain.doFilter () pārsūtīt pieprasījumu. Servleta formāta filtri nav nepieciešami, lai piezvanītu chain.doFilter (); ja viņi to nedara, pieprasījums netiek pārsūtīts. Es varu pievienot vairāk filtru, kas tiek izsaukti tādā secībā, kādā tie ir deklarēti iepriekšējā XML failā.

Tagad, kad esat redzējis vienkāršu filtru, apskatīsim citu filtru, kas modificē HTTP atbildi.

Filtrējiet atbildi ar dekoratora modeli

Atšķirībā no iepriekšējā filtra, dažiem servletu filtriem ir jāmaina HTTP pieprasījums vai atbilde. Interesanti, ka šis uzdevums ir saistīts ar dekoratora modeli. Dekoratora modeli es apspriedu divos iepriekšējos Java dizaina modeļi raksti: "Pārsteidziet savus izstrādātāja draugus ar dizaina modeļiem" un "Izrotājiet savu Java kodu".

4. piemērā ir uzskaitīts filtrs, kas atbildes pamattekstā veic vienkāršu meklēšanu un aizstāšanu. Šis filtrs rotā servletes reakciju un nodod dekoratoru servletai. Kad servelets pabeidz rakstīt uz dekorēto atbildi, filtrs veic meklēšanu un aizvietošanu atbildes saturā.

4. piemērs. Meklēšanas un aizstāšanas filtrs

importēt java.io. *; importēt javax.servlet. *; importēt javax.servlet.http. *; publiskā klase SearchAndReplaceFilter ievieš filtru {private FilterConfig config; public void init (FilterConfig config) {this.config = config; } public FilterConfig getFilterConfig () {return config; } public void doFilter (ServletRequest pieprasījums, ServletResponse atbilde, FilterChain ķēde) meta java.io.IOException, javax.servlet.ServletException {StringWrapper iesaiņotājs = jauns StringWrapper((HttpServletResponse) atbilde); chain.doFilter(pieprasījums, iesaiņojums); String responseString = iesaiņotājs.toString(); Virknes meklēšana = config.getInitParameter ("meklēšana"); Virkne aizstāt = config.getInitParameter ("aizstāt"); if (search == null || aizstāt == null) return; // Parametri nav pareizi iestatīti int index = responseString.indexOf (meklēšana); if (indekss! = -1) {String beforeReplace = responseString.substring (0, indekss); String afterReplace = responseString.substring (indekss + meklēšana.length ()); response.getWriter (). izdrukāt(beforeReplace + aizstāt + afterReplace); }} public void iznīcināt () {config = null; }} 

Iepriekšējais filtrs meklē nosauktos filtru iniciēšanas parametrus Meklēt un aizvietot; ja tie ir definēti, filtrs aizstāj pirmo Meklēt parametra vērtība ar aizvietot parametra vērtība.

SearchAndReplaceFilter.doFilter () ietin (vai rotā) atbildes objektu ar iesaiņotāju (dekoratoru), kas iestājas atbildē. Kad SearchAndReplaceFilter.doFilter () zvani chain.doFilter () lai pārsūtītu pieprasījumu, tas ietina iesaiņotāju sākotnējās atbildes vietā. Pieprasījums tiek pārsūtīts uz servletīklu, kas ģenerē atbildi.

Kad chain.doFilter () atgriežas, servlets ir paveikts ar lūgumu, tāpēc es eju uz darbu. Pirmkārt, es pārbaudu Meklēt un aizvietot filtru parametri; ja ir, es iegūstu virkni, kas saistīta ar atbildes iesaiņotāju, kas ir atbildes saturs. Tad es veicu nomaiņu un izdrukāju to atpakaļ uz atbildi.

5. piemērā ir uzskaitīti StringWrapper klasē.

5. piemērs. Dekorators

importēt java.io. *; importēt javax.servlet. *; importēt javax.servlet.http. *; publiskā klase StringWrapper paplašina HttpServletResponseWrapper {StringWriter rakstītājs = new StringWriter (); public StringWrapper (HttpServletResponse response) {super (atbilde); } public PrintWriter getWriter () {return new PrintWriter (rakstnieks); } public String toString () {return liter.toString (); }} 

StringWrapper, kas rotā HTTP atbildi 4. piemērā, ir HttpServletResponseWrapper, kas mūs saudzē ar dekoratoru bāzes klases izveidošanu, lai dekorētu HTTP atbildes. HttpServletResponseWrapper galu galā īsteno ServletResponse interfeisu, tāpēc HttpServletResponseWrapper var nodot jebkurai metodei, kas sagaida a ServletResponse objekts. Tāpēc SearchAndReplaceFilter.doFilter () var piezvanīt chain.doFilter (pieprasījums, iesaiņojums) tā vietā chain.doFilter (pieprasījums, atbildi).

Tagad, kad mums ir filtrs un atbildes iesaiņotājs, saistīsim filtru ar URL rakstu un norādīsim meklēšanas un aizstāšanas modeļus:

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