Programmering

Et kig på det sammensatte designmønster

Forleden lyttede jeg til National Public Radio Bil samtale, en populær ugentlig udsendelse, hvor opkaldere stiller spørgsmål om deres køretøjer. Før hver programpause beder showets værter opkaldere om at ringe til 1-800-CAR-TALK, hvilket svarer til 1-800-227-8255. Selvfølgelig viser det førstnævnte sig meget lettere at huske end det sidstnævnte, delvis fordi ordene "BILTALK" er en sammensætning: to ord, der repræsenterer syv cifre. Mennesker har generelt det lettere at håndtere kompositter snarere end deres individuelle komponenter. Ligeledes, når du udvikler objektorienteret software, er det ofte praktisk at manipulere kompositter, ligesom du manipulerer individuelle komponenter. Denne forudsætning repræsenterer det grundlæggende princip i det sammensatte designmønster, emnet for dette Java designmønstre rate.

Det sammensatte mønster

Før vi dykker ned i det sammensatte mønster, skal jeg først definere sammensatte objekter: genstande, der indeholder andre genstande for eksempel kan en tegning være sammensat af grafiske primitiver, såsom linjer, cirkler, rektangler, tekst osv.

Java-udviklere har brug for det sammensatte mønster, fordi vi ofte skal manipulere kompositter nøjagtigt på samme måde, som vi manipulerer primitive objekter. For eksempel skal grafiske primitiver såsom linjer eller tekst tegnes, flyttes og ændres. Men vi ønsker også at udføre den samme operation på kompositter, såsom tegninger, der er sammensat af disse primitiver. Ideelt set vil vi gerne udføre operationer på både primitive objekter og kompositter på nøjagtig samme måde, uden at skelne mellem de to. Hvis vi skal skelne mellem primitive objekter og kompositter for at udføre de samme operationer på disse to typer objekter, ville vores kode blive mere kompleks og vanskeligere at implementere, vedligeholde og udvide.

I Designmønstrebeskriver forfatterne det sammensatte mønster som dette:

Komponer objekter i træstrukturer for at repræsentere del-hele hierarkier. Composite lader klienter behandle individuelle objekter og kompositioner af objekter ensartet.

Implementering af det sammensatte mønster er let. Kompositklasser udvider en basisklasse, der repræsenterer primitive objekter. Figur 1 viser et klassediagram, der illustrerer kompositmønsterets struktur.

I figur 1s klassediagram brugte jeg klassenavne fra Designmønster 's Sammensat diskussionsmønster: Komponent repræsenterer en basisklasse (eller muligvis en grænseflade) for primitive objekter, og Sammensatte repræsenterer en sammensat klasse. F.eks Komponent klasse kan repræsentere en basisklasse for grafiske primitiver, mens Sammensatte klasse kan repræsentere en Tegning klasse. Figur 1'er Blad klasse repræsenterer et konkret primitivt objekt; for eksempel en Linie klasse eller en Tekst klasse. Det Operation1 () og Operation2 () metoder repræsenterer domænespecifikke metoder implementeret af begge Komponent og Sammensatte klasser.

Det Sammensatte klasse vedligeholder en samling af komponenter. Typisk, Sammensatte Metoder implementeres ved at gentage over denne samling og påkalde den passende metode til hver Komponent i samlingen. F.eks Tegning klasse kan implementere sin tegne() metode som denne:

// Denne metode er en sammensat metode offentlig ugyldig tegning () {// Iterer over komponenterne for (int i = 0; i <getComponentCount (); ++ i) {// Få en reference til komponenten og påberåbe sig tegningen metode Komponentkomponent = getComponent (i); component.draw (); }} 

For hver metode implementeret i Komponent klasse, den Sammensatte klasse implementerer en metode med den samme signatur, som gentager sig over kompositets komponenter, som illustreret af tegne() ovennævnte metode.

Det Sammensatte klasse udvider Komponent klasse, så du kan videregive en komposit til en metode, der forventer en komponent; overvej f.eks. følgende metode:

// Denne metode er implementeret i en klasse, der ikke er relateret til // Komponent- og kompositklasser offentlig ugyldig genmaling (komponentkomponent) {// Komponenten kan være en sammensat, men da den udvider // komponentklassen, behøver denne metode ikke // skelne mellem komponenter og kompositter component.draw (); } 

Den foregående metode sendes en komponent - enten en simpel komponent eller et komposit - så påkalder den komponentens tegne() metode. Fordi Sammensatte klasse udvides Komponent, det genmaling () metoden behøver ikke at skelne mellem komponenter og kompositter - den påberåber sig blot tegne() metode til komponenten (eller kompositten).

Figur 1's sammensatte mønster klassediagram illustrerer et problem med mønsteret: Du skal skelne mellem komponenter og kompositter, når du refererer til en Komponent, og du skal påberåbe en sammensat-specifik metode, f.eks addComponent (). Du opfylder typisk dette krav ved at tilføje en metode, f.eks isComposite (), til Komponent klasse. Denne metode vender tilbage falsk for komponenter og er tilsidesat i Sammensatte klasse at vende tilbage rigtigt. Derudover skal du også kaste Komponent henvisning til en Sammensatte eksempel, som denne:

... hvis (component.isComposite ()) {Composite composite = (Composite) komponent; composite.addComponent (someComponentThatCouldBeAComposite); } ... 

Bemærk, at addComponent () metoden er bestået a Komponent reference, som enten kan være en primitiv komponent eller en komposit. Fordi denne komponent kan være en komposit, kan du komponere komponenter i en træstruktur, som angivet med ovennævnte citat fra Designmønstre.

Figur 2 viser en alternativ implementering af sammensatte mønstre.

Hvis du implementerer figur 2s sammensatte mønster, behøver du ikke nogensinde at skelne mellem komponenter og kompositter, og du behøver ikke at kaste en Komponent henvisning til en Sammensatte eksempel. Så kodefragmentet, der er anført ovenfor, reduceres til en enkelt linje:

... component.addComponent (someComponentThatCouldBeAComposite); ... 

Men hvis Komponent reference i det foregående kode fragment henviser ikke til a Sammensatte, hvad skal addComponent () gøre? Det er et vigtigt stridspunkt med implementering af figur 2's sammensatte mønster. Fordi primitive komponenter ikke indeholder andre komponenter, giver det ingen mening at tilføje en komponent til en anden komponent, så det Component.addComponent () Metoden kan enten fejle lydløst eller kaste en undtagelse. Typisk betragtes tilføjelse af en komponent til en anden primitiv komponent som en fejl, så det er måske den bedste fremgangsmåde at kaste en undtagelse.

Så hvilken implementering af sammensat mønster - den i figur 1 eller den i figur 2 - fungerer bedst? Det er altid et emne med stor debat blandt implementere af sammensatte mønstre; Designmønstre foretrækker implementering af figur 2, fordi du aldrig behøver at skelne mellem komponenter og containere, og du behøver aldrig at udføre en rollebesætning. Personligt foretrækker jeg implementering af figur 1, fordi jeg har en stærk modvilje mod at implementere metoder i en klasse, der ikke giver mening for den objekttype.

Nu hvor du forstår det sammensatte mønster, og hvordan du kan implementere det, lad os undersøge et eksempel på et sammensat mønster med Apache Struts JavaServer Pages (JSP) -rammen.

Komposit mønster og stivere fliser

Apache Struts-rammen inkluderer et JSP-tagbibliotek, kendt som Tiles, der lader dig komponere en webside fra flere JSP'er. Tiles er faktisk en implementering af J2EE (Java 2 Platform, Enterprise Edition) CompositeView-mønster, selv baseret på Designmønstre Sammensat mønster. Før vi diskuterer det sammensatte mønsters relevans for fliser-tagbiblioteket, lad os først gennemgå begrundelsen for fliser, og hvordan du bruger det. Hvis du allerede er fortrolig med Struts Tiles, kan du skimme de følgende sektioner og begynde at læse under "Brug det sammensatte mønster med Struts Tiles."

Bemærk: Du kan læse mere om J2EE CompositeView-mønsteret i min "Komponenter til webapplikationer lavet let med kompositvisning" (JavaWorld, December 2001) artikel.

Designere konstruerer ofte websider med et sæt diskrete regioner; for eksempel omfatter figur 3s webside en sidebjælke, sidehoved, indholdsregion og sidefod.

Hjemmesider inkluderer ofte flere websider med identiske layout, såsom figur 3's sidepanel / sidehoved / indhold / sidefodslayout. Struts Tiles giver dig mulighed for at genbruge både indhold og layout på flere websider. Før vi diskuterer genbrug, lad os se, hvordan figur 3s layout traditionelt implementeres med HTML alene.

Implementere komplekse layouts manuelt

Eksempel 1 viser, hvordan du kan implementere figur 3s webside med HTML:

Eksempel 1. Et komplekst layout implementeret i hånden

    Implementering af komplekse layout med hånden <% - En tabel viser alt indholdet på denne side -%>
Links

Hjem

Produkter

Downloads

Hvidbøger

Kontakt os

Velkommen til Sabreware, Inc.
Sidespecifikt indhold kommer her

Tak fordi du kom forbi!

Den foregående JSP har to store ulemper: For det første er sidens indhold indlejret i JSP, så du kan ikke genbruge noget af det, selvom sidepanelet, sidehovedet og sidefoden sandsynligvis vil være det samme på mange websider. For det andet er sidens layout også indlejret i den JSP, så du kan heller ikke genbruge det, selvom mange andre websider på det samme websted bruger det samme layout. Vi kan bruge handling for at afhjælpe den første ulempe, som jeg diskuterer næste.

Implementere komplekse layouts med JSP inkluderer

Eksempel 2 viser en implementering af figur 3s webside, der bruger :