Pred dnevi sem poslušal Radio Javnega radia Car Talk, priljubljena tedenska oddaja, med katero kličoči postavljajo vprašanja o svojih vozilih. Pred vsakim odmorom programa voditelji oddaje prosijo klicatelje, da pokličejo 1-800-CAR-TALK, kar ustreza 1-800-227-8255. Seveda se je prvega veliko lažje zapomniti kot drugega, deloma zato, ker so besede "CAR TALK" sestavljene: dve besedi, ki predstavljata sedem števk. Ljudje se na splošno lažje soočamo s kompoziti in ne s posameznimi komponentami. Podobno je pri razvoju objektno usmerjene programske opreme pogosto priročno manipulirati s kompoziti, tako kot manipulirati s posameznimi komponentami. Ta predpostavka predstavlja temeljno načelo vzorca kompozitnega oblikovanja, tema tega Vzorci Java oblikovanja obrok.
Sestavljeni vzorec
Preden se potopimo v sestavljeni vzorec, moram najprej določiti sestavljeni predmeti: predmeti, ki vsebujejo druge predmete; na primer, risba je lahko sestavljena iz grafičnih primitivov, kot so črte, krogi, pravokotniki, besedilo itd.
Razvijalci Java potrebujejo sestavljeni vzorec, ker moramo s kompoziti pogosto ravnati popolnoma enako kot s primitivnimi predmeti. Na primer, grafične primitive, kot so črte ali besedilo, je treba narisati, premakniti in spremeniti velikost. Toda isto operacijo želimo izvesti tudi na kompozitih, kot so risbe, ki so sestavljene iz teh primitivov. V idealnem primeru bi radi izvajali operacije tako na primitivnih predmetih kot na kompozitih na popolnoma enak način, brez razlikovanja med obema. Če moramo razlikovati med primitivnimi predmeti in sestavljenimi elementi za izvajanje enakih operacij na teh dveh vrstah predmetov, bi naša koda postala bolj zapletena in težja za izvajanje, vzdrževanje in razširitev.
V Vzorci oblikovanja, avtorji opisujejo sestavljeni vzorec tako:
Sestavite predmete v drevesne strukture, da predstavljajo delno cele hierarhije. Kompozit omogoča strankam, da posamezne predmete in sestave predmetov obravnavajo enakomerno.Izvajanje kompozitnega vzorca je enostavno. Sestavljeni razredi razširjajo osnovni razred, ki predstavlja primitivne predmete. Slika 1 prikazuje diagram razredov, ki prikazuje strukturo sestavljenega vzorca.
V diagramu razredov na sliki 1 sem uporabil imena razredov iz Vzorec oblikovanja 's Razprava o sestavljenem vzorcu: Komponenta
predstavlja osnovni razred (ali morda vmesnik) za primitivne predmete in Sestavljen
predstavlja sestavljeni razred. Na primer Komponenta
razred lahko predstavlja osnovni razred za grafične primitive, medtem ko Sestavljen
razred lahko predstavlja a Risba
razred. Slika 1 List
razred predstavlja konkreten primitivni objekt; na primer a Vrstica
razred ali a Besedilo
razred. The Operacija1 ()
in Operacija2 ()
metode predstavljajo metode, specifične za področje, ki jih izvajata obe Komponenta
in Sestavljen
razredih.
The Sestavljen
razred vzdržuje zbirko komponent. Običajno Sestavljen
metode se izvajajo s ponovitvijo te zbirke in za vsako uporabo ustrezne metode Komponenta
v zbirki. Na primer, a Risba
razred lahko izvede svoj žreb ()
metoda, kot je ta:
// Ta metoda je sestavljena metoda public void draw () {// Iteracija nad komponentami za (int i = 0; i <getComponentCount (); ++ i) {// Pridobite sklic na komponento in prikliči njeno risanje metoda Komponenta komponenta = getComponent (i); component.draw (); }}
Za vsako metodo, izvedeno v Komponenta
razred, Sestavljen
class izvaja metodo z enakim podpisom, ki se ponovi nad sestavljenimi komponentami, kot je prikazano v žreb ()
zgoraj navedena metoda.
The Sestavljen
razred podaljša Komponenta
razreda, tako da lahko sestavljeni del predate metodi, ki pričakuje komponento; na primer razmislite o naslednji metodi:
// Ta metoda je izvedena v razredu, ki ni povezan z // javnim praznim prebarvanjem (komponentna komponenta) razredov Component in Composite class {// Komponenta je lahko sestavljena, vendar ker ta razširja // razred Component, te metode ni treba // ločimo med komponentami in sestavljenimi komponentami.draw (); }
Prejšnji metodi se posreduje komponenta - ali preprosta komponenta ali kompozit - in nato prikliče komponento žreb ()
metoda. Zaradi Sestavljen
razred se razširi Komponenta
, prebarvati ()
metode ni treba razlikovati med sestavnimi deli in kompoziti - preprosto prikliče žreb ()
metoda za komponento (ali sestavljeno).
Diagram razredov sestavljenega vzorca na sliki 1 ponazarja eno težavo z vzorcem: pri sklicevanju na komponento in kompozit morate razlikovati Komponenta
, in morate uporabiti sestavljeno metodo, kot je addComponent ()
. To zahtevo običajno izpolnite z dodajanjem metode, kot je isComposite ()
, do Komponenta
razred. Ta metoda se vrne napačno
za komponente in je v Sestavljen
razred za vrnitev prav
. Poleg tega morate predvajati tudi Komponenta
sklic na a Sestavljen
primer, kot je ta:
... if (component.isComposite ()) {Composite composite = (Composite) komponenta; composite.addComponent (someComponentThatCouldBeAComposite); } ...
Upoštevajte, da addComponent ()
metoda je posredovana a Komponenta
sklic, ki je lahko bodisi primitivna komponenta bodisi sestavljena. Ker je ta komponenta lahko sestavljena, lahko sestavite sestavne dele v drevesno strukturo, kot kaže zgoraj omenjeni citat iz Vzorci oblikovanja.
Slika 2 prikazuje alternativno izvedbo sestavljenega vzorca.
Če uporabite kompozitni vzorec slike 2, vam ni treba nikoli razlikovati med komponentami in kompoziti ter vam ni treba oddati Komponenta
sklic na a Sestavljen
primer. Torej zgoraj navedeni fragment kode se zmanjša v eno vrstico:
... component.addComponent (someComponentThatCouldBeAComposite); ...
Ampak, če Komponenta
sklic v prejšnjem fragmentu kode se ne nanaša na a Sestavljen
, kaj naj addComponent ()
narediti? To je glavno sporno vprašanje pri izvajanju sestavljenega vzorca na sliki 2. Ker primitivne komponente ne vsebujejo drugih komponent, dodajanje komponente drugi komponenti nima smisla, zato Component.addComponent ()
metoda lahko tiho odpove ali vrne izjemo. Običajno dodajanje komponente drugi primitivni komponenti velja za napako, zato je metanje izjeme morda najboljši način ukrepanja.
Katera izvedba sestavljenega vzorca - tista na sliki 1 ali tista na sliki 2 - deluje najbolje? To je vedno tema velike razprave med izvajalci kompozitnih vzorcev; Vzorci oblikovanja raje izvajanje slike 2, ker vam nikoli ni treba razlikovati med komponentami in vsebniki in vam ni treba izvesti zasedbe. Osebno imam raje izvedbo slike 1, ker imam močno odpor do izvajanja metod v razredu, ki za ta tip objekta niso smiselne.
Zdaj, ko razumete sestavljeni vzorec in kako ga lahko izvedete, preučimo primer sestavljenega vzorca z ogrodjem Apache Struts JavaServer Pages (JSP).
Sestavljeni vzorec in ploščice
Okvir Apache Struts vključuje knjižnico oznak JSP, imenovano Tiles, ki vam omogoča sestavljanje spletne strani iz več JSP-jev. Tiles je pravzaprav izvedba vzorca J2EE (Java 2 Platform, Enterprise Edition) CompositeView, ki sam temelji na Vzorci oblikovanja Sestavljen vzorec. Preden se pogovorimo o pomembnosti sestavljenega vzorca za knjižnico ploščic Tiles, najprej preglejmo utemeljitev ploščic in kako jo uporabljate. Če že poznate ploščice Struts, lahko preberete naslednje razdelke in začnete z branjem pri "Uporabite sestavljeni vzorec s ploščicami Struts."
Opomba: Več o vzorcu J2EE CompositeView si lahko preberete v mojem članku »Komponente spletne aplikacije, ki so olajšane s sestavljenim pogledom« (JavaWorld, December 2001) članek.
Oblikovalci pogosto gradijo spletne strani z naborom ločenih regij; na primer, spletna stran slike 3 vsebuje stransko vrstico, glavo, področje vsebine in nogo.
Spletna mesta pogosto vključujejo več spletnih strani z enakimi postavitvami, na primer postavitev stranske vrstice / glave / vsebine / noge na sliki 3. Struts Tiles omogoča ponovno uporabo vsebine in postavitve na več spletnih straneh. Preden se pogovorimo o tej ponovni uporabi, poglejmo, kako se postavitev slike 3 tradicionalno izvaja samo z HTML-jem.
Ročno izvedite zapletene postavitve
Primer 1 prikazuje, kako lahko implementirate spletno stran slike 3 z HTML-jem:
Primer 1. Kompleksna postavitev, izvedena ročno
Ročno izvajanje zapletenih postavitev <% - Ena tabela vsebuje vso vsebino te strani -%>
|
|
Prejšnji JSP ima dve glavni pomanjkljivosti: Prvič, vsebina strani je vdelana v JSP, zato je ne morete znova uporabiti, čeprav so stranska vrstica, glava in noga verjetno enaki na številnih spletnih straneh. Drugič, postavitev strani je prav tako vdelana v ta JSP, zato je tudi ne morete ponovno uporabiti, čeprav številne druge spletne strani na istem spletnem mestu uporabljajo isto postavitev. Lahko uporabimo ukrepanje za odpravo prve pomanjkljivosti, o čemer bom razpravljal v nadaljevanju.
Izvedite zapletene postavitve z JSP
Primer 2 prikazuje izvedbo spletne strani slike 3, ki jo uporablja :