Programmering

En titt på det sammensatte designmønsteret

Forleden hørte jeg på National Public Radio Car Talk, en populær ukentlig sending der innringere stiller spørsmål om kjøretøyene sine. Før hver programpause ber programets verter innringere ringe 1-800-CAR-TALK, som tilsvarer 1-800-227-8255. Selvfølgelig viser førstnevnte seg mye lettere å huske enn sistnevnte, delvis fordi ordene "CAR TALK" er en kompositt: to ord som representerer syv sifre. Mennesker synes generelt det er lettere å håndtere kompositter, i stedet for deres individuelle komponenter. På samme måte, når du utvikler objektorientert programvare, er det ofte praktisk å manipulere kompositter akkurat som du manipulerer individuelle komponenter. Denne forutsetningen representerer det grunnleggende prinsippet for det sammensatte designmønsteret, temaet for dette Java Design Patterns avdrag.

Komposittmønsteret

Før vi dykker inn i det sammensatte mønsteret, må jeg først definere sammensatte objekter: gjenstander som inneholder andre gjenstander; for eksempel kan en tegning være sammensatt av grafiske primitiver, som linjer, sirkler, rektangler, tekst og så videre.

Java-utviklere trenger det sammensatte mønsteret fordi vi ofte må manipulere kompositter nøyaktig på samme måte som vi manipulerer primitive objekter. For eksempel må grafiske primitiver som linjer eller tekst tegnes, flyttes og endres. Men vi vil også utføre den samme operasjonen på kompositter, som tegninger, som er sammensatt av disse primitivene. Ideelt sett vil vi utføre operasjoner på både primitive gjenstander og kompositter på nøyaktig samme måte, uten å skille mellom de to. Hvis vi må skille mellom primitive objekter og kompositter for å utføre de samme operasjonene på de to typene objekter, ville koden vår blitt mer kompleks og vanskeligere å implementere, vedlikeholde og utvide.

I Design mønstrebeskriver forfatterne det sammensatte mønsteret slik:

Komponer objekter i trestrukturer for å representere hierarkier fra hele deler. Composite lar kunder behandle individuelle objekter og komposisjoner av objekter jevnt.

Det er enkelt å implementere komposittmønsteret. Sammensatte klasser utvider en basisklasse som representerer primitive objekter. Figur 1 viser et klassediagram som illustrerer strukturen til det sammensatte mønsteret.

I figur 1s klassediagram brukte jeg klassenavn fra Design mønster's Sammensatt mønsterdiskusjon: Komponent representerer en basisklasse (eller muligens et grensesnitt) for primitive objekter, og Sammensatte representerer en sammensatt klasse. For eksempel Komponent klasse kan representere en basisklasse for grafiske primitiver, mens Sammensatte klasse kan representere en Tegning klasse. Figur 1 Blad klasse representerer et konkret primitivt objekt; for eksempel en Linje klasse eller a Tekst klasse. De Operasjon1 () og Operasjon2 () metoder representerer domenespesifikke metoder implementert av begge Komponent og Sammensatte klasser.

De Sammensatte klasse vedlikeholder en samling av komponenter. Typisk, Sammensatte metodene er implementert ved å gjenta over samlingen og påkalle den riktige metoden for hver Komponent i samlingen. For eksempel, a Tegning klasse kan implementere sin tegne() metode som denne:

// Denne metoden er en sammensetningsmetode public void draw () {// Iterer over komponentene for (int i = 0; i <getComponentCount (); ++ i) {// Få en referanse til komponenten og påkalle tegningen metode Komponentkomponent = getComponent (i); component.draw (); }} 

For hver metode implementert i Komponent klasse, den Sammensatte klasse implementerer en metode med samme signatur som gjentas over komposittkomponentene, som illustrert av tegne() metoden som er oppført ovenfor.

De Sammensatte klasse utvider Komponent klasse, slik at du kan overføre en kompositt til en metode som forventer en komponent; Tenk for eksempel på følgende metode:

// Denne metoden er implementert i en klasse som ikke er relatert til // Component and Composite class public void repaint (Component component) {// Komponenten kan være en kompositt, men siden den utvides // Component-klassen, trenger denne metoden ikke // skille mellom komponenter og kompositter component.draw (); } 

Den foregående metoden er sendt en komponent - enten en enkel komponent eller en kompositt - så påkaller den komponenten tegne() metode. Fordi det Sammensatte klasse utvider Komponent, den male på nytt () metoden trenger ikke å skille mellom komponenter og kompositter - den påkaller ganske enkelt tegne() metode for komponenten (eller kompositt).

Figur 1s sammensatte mønster klassediagram illustrerer ett problem med mønsteret: du må skille mellom komponenter og kompositter når du refererer til en Komponent, og du må påberope en kompositt-spesifikk metode, for eksempel addComponent (). Du oppfyller vanligvis dette kravet ved å legge til en metode, for eksempel isComposite (), til Komponent klasse. Den metoden kommer tilbake falsk for komponenter og overstyres i Sammensatte klasse å komme tilbake ekte. I tillegg må du også kaste Komponent henvisning til a Sammensatte eksempel, slik:

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

Legg merke til at addComponent () metoden er bestått a Komponent referanse, som enten kan være en primitiv komponent eller en kompositt. Fordi komponenten kan være en kompositt, kan du komponere komponentene i en trestruktur, som angitt av det nevnte sitatet fra Design mønstre.

Figur 2 viser en alternativ implementering av sammensatt mønster.

Hvis du implementerer figur 2s sammensatte mønster, trenger du aldri å skille mellom komponenter og kompositter, og du trenger ikke å kaste en Komponent henvisning til a Sammensatte forekomst. Så kodefragmentet som er oppført ovenfor, reduseres til en enkelt linje:

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

Men hvis den Komponent referanse i forrige kodefragment refererer ikke til a Sammensatte, hva skal addComponent () gjøre? Det er et viktig stridspunkt med figur 2s implementering av sammensatt mønster. Fordi primitive komponenter ikke inneholder andre komponenter, gir det ingen mening å legge til en komponent i en annen komponent Component.addComponent () metoden kan enten mislykkes lydløst eller kaste et unntak. Vanligvis betraktes det som en feil å legge til en komponent i en annen primitiv komponent, så å kaste et unntak er kanskje den beste fremgangsmåten.

Så hvilken implementering av sammensatt mønster - den i figur 1 eller den i figur 2 - fungerer best? Det er alltid et tema for god debatt blant implementatorer av sammensatte mønstre; Design mønstre foretrekker figur 2-implementeringen fordi du aldri trenger å skille mellom komponenter og containere, og du trenger aldri å utføre en rollebesetning. Personlig foretrekker jeg implementering av figur 1, fordi jeg har en sterk aversjon mot å implementere metoder i en klasse som ikke gir mening for den objekttypen.

Nå som du forstår det sammensatte mønsteret og hvordan du kan implementere det, la oss undersøke et eksempel på et sammensatt mønster med Apache Struts JavaServer Pages (JSP) rammeverk.

Komposittmønsteret og Struts Tiles

Apache Struts-rammeverket inkluderer et JSP-tagbibliotek, kjent som Tiles, som lar deg komponere en webside fra flere JSPer. Tiles er faktisk en implementering av J2EE (Java 2 Platform, Enterprise Edition) CompositeView-mønster, basert på Design mønstre Sammensatt mønster. Før vi diskuterer det sammensatte mønsterets relevans for fliser-tagbiblioteket, la oss først gjennomgå begrunnelsen for fliser, og hvordan du bruker den. Hvis du allerede er kjent med Struts Tiles, kan du gå gjennom følgende seksjoner og begynne å lese på "Bruk det sammensatte mønsteret med Struts Tiles."

Merk: Du kan lese mer om J2EE CompositeView-mønsteret i "Web Application Components Made Easy with Composite View" (JavaWorld, Desember 2001) artikkel.

Designere lager ofte nettsider med et sett med diskrete regioner; for eksempel omfatter figur 3s webside en sidefelt, topptekst, innholdsregion og bunntekst.

Nettsteder inkluderer ofte flere nettsider med identiske oppsett, for eksempel figur 3s sidefelt / topptekst / innhold / bunntekstoppsett. Struts Tiles lar deg bruke både innhold og layout på flere websider. Før vi diskuterer gjenbruk, la oss se hvordan figur 3s layout tradisjonelt er implementert med HTML alene.

Implementere komplekse oppsett for hånd

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

Eksempel 1. Et komplekst oppsett implementert for hånd

    Implementering av komplekse oppsett for hånd <% - Én tabell viser alt innholdet på denne siden -%>
Lenker

Hjem

Produkter

Nedlastinger

hvite papirer

Kontakt oss

Velkommen til Sabreware, Inc.
Sidespesifikk innhold går her

Takk for at du kom innom!

Den forrige JSP har to store ulemper: For det første er innholdet på siden innebygd i JSP, så du kan ikke gjenbruke noe av det, selv om sidefelt, topptekst og bunntekst sannsynligvis vil være det samme på mange nettsider. For det andre er sidens layout også innebygd i den JSP, så du kan heller ikke bruke den igjen, selv om mange andre websider på samme nettsted bruker samme layout. Vi kan bruke handling for å avhjelpe den første ulempen, som jeg diskuterer neste.

Implementere komplekse oppsett med JSP inkluderer

Eksempel 2 viser en implementering av figur 3s webside som bruker :