Поглед към модела на композитния дизайн

Онзи ден слушах Car Talk на Националното обществено радио , популярно седмично предаване, по време на което обаждащите се задават въпроси за своите превозни средства. Преди всяка почивка на програмата, водещите на предаването молят повикващите да наберат 1-800-CAR-TALK, което съответства на 1-800-227-8255. Разбира се, първото се оказва много по-лесно за запомняне от второто, отчасти защото думите „CAR TALK“ са съставни: две думи, които представляват седем цифри. Хората обикновено имат по-лесно да се справят с композитите, а не с отделните им компоненти. По същия начин, когато разработвате обектно-ориентиран софтуер, често е удобно да манипулирате композити точно както манипулирате отделни компоненти. Тази предпоставка представлява основния принцип на композитния дизайн,темата на този модел на Java вноска.

Композитният модел

Преди да се потопим в композитния модел, първо трябва да дефинирам съставни обекти: обекти, които съдържат други обекти; например чертежът може да се състои от графични примитиви, като линии, кръгове, правоъгълници, текст и т.н.

Разработчиците на Java се нуждаят от композитния модел, защото често трябва да манипулираме композитите по същия начин, по който манипулираме примитивните обекти. Например графичните примитиви като линии или текст трябва да бъдат изчертани, преместени и преоразмерени. Но ние също искаме да извършим същата операция върху композити, като рисунки, които са съставени от тези примитиви. В идеалния случай бихме искали да извършваме операции както върху примитивни обекти, така и върху композити по абсолютно същия начин, без да правим разлика между двете. Ако трябва да правим разлика между примитивни обекти и композити, за да изпълняваме едни и същи операции върху тези два типа обекти, нашият код ще стане по-сложен и по-труден за внедряване, поддържане и разширяване.

В дизайнерски модели авторите описват композитния модел така:

Композирайте обекти в дървесни структури, за да представите частично цели йерархии. Композит позволява на клиентите да се отнасят еднакво към отделни предмети и композиции от предмети.

Внедряването на композитния модел е лесно. Композитните класове разширяват базовия клас, който представлява примитивни обекти. Фигура 1 показва диаграма на класа, която илюстрира структурата на композитния модел.

В диаграмата на класове на Фигура 1 използвах имена на класове от дискусията на Composite pattern на Design Pattern : Componentпредставлява основен клас (или евентуално интерфейс) за примитивни обекти и Compositeпредставлява композитен клас. Например Componentкласът може да представлява основен клас за графични примитиви, докато Compositeкласът може да представлява Drawingклас. LeafКласът на фигура 1 представлява конкретен примитивен обект; например Lineклас или Textклас. Методите Operation1()and Operation2()представляват специфични за домейна методи, внедрени както от класовете, така Componentи от Composite.

В Compositeкласа поддържа колекция от компоненти. Обикновено Compositeметодите се изпълняват чрез итерация над тази колекция и извикване на подходящия метод за всеки Componentв колекцията. Например, Drawingклас може да приложи своя draw()метод по следния начин:

// Този метод е композитен метод public void draw () {// Итерация над компонентите за (int i = 0; i <getComponentCount (); ++ i) {// Получаване на препратка към компонента и извикване на неговото теглене метод Компонент компонент = getComponent (i); component.draw (); }}

За всеки метод, реализиран в Componentкласа, Compositeкласът реализира метод със същия подпис, който се итерира върху компонентите на композита, както е илюстрирано от draw()метода, изброен по-горе.

В Compositeклас разширява Componentкласа, така че може да премине съставна до метод, който очаква компонент; например, помислете за следния метод:

// Този метод е реализиран в клас, който няма връзка с // Component и Composite класове public void repaint (Component komponenta) {// Компонентът може да бъде композитен, но тъй като се разширява // Component class, този метод не е необходимо // разграничаване между компоненти и композити компонент.draw (); }

Предходният метод се предава на компонент - или обикновен компонент, или композит - след това той извиква draw()метода на този компонент . Тъй като Compositeкласът се разширява Component, repaint()методът не трябва да прави разлика между компоненти и композити - той просто извиква draw()метода за компонента (или композит).

Composite схема, клас Фигура 1 е прави илюстрира един проблем с модела: трябва да се прави разлика между компоненти и композити, когато позоваване на Component, и трябва да се позове метод композитен-специфични, като addComponent(). Обикновено изпълнявате това изискване, като добавяте метод, като например isComposite(), към Componentкласа. Този метод се връща falseза компоненти и се заменя в Compositeкласа, за да се върне true. Освен това трябва да хвърлите Componentпрепратката към Compositeекземпляр, като този:

... if (component.isComposite ()) {Composite composite = (Composite) компонент; composite.addComponent (someComponentThatCouldBeAComposite); } ...

Забележете, че на addComponent()метода се предава Componentреференция, която може да бъде или примитивен компонент, или композитен. Тъй като този компонент може да бъде композитен, можете да композирате компоненти в дървовидна структура, както е посочено от гореспоменатия цитат от Design Patterns .

Фигура 2 показва алтернативно изпълнение на композитен модел.

Ако внедрите Композитния модел на Фигура 2, никога няма да се налага да правите разлика между компоненти и композити и не е нужно да подавате Componentпрепратка към Compositeекземпляр. Така изброеният по-горе фрагмент на кода се свежда до един ред:

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

Но ако Componentпрепратката в предходния кодов фрагмент не се отнася до a Composite, какво трябва да се addComponent()направи? Това е основна спорна точка с изпълнението на композитния модел на Фигура 2. Тъй като примитивните компоненти не съдържат други компоненти, добавянето на компонент към друг компонент няма смисъл, така че Component.addComponent()методът може или да се провали безшумно, или да изведе изключение. Обикновено добавянето на компонент към друг примитивен компонент се счита за грешка, така че хвърлянето на изключение е може би най-добрият начин на действие.

И така, кое изпълнение на композитен модел - това на фигура 1 или това на фигура 2 - работи най-добре? Това винаги е тема на голям дебат сред изпълнителите на композитни модели; Design Patterns предпочита изпълнението на Фигура 2, защото никога не е необходимо да правите разлика между компоненти и контейнери и никога не е необходимо да изпълнявате гласове. Лично аз предпочитам изпълнението на Фигура 1, тъй като имам силно отвращение към прилагането на методи в клас, които нямат смисъл за този тип обект.

Сега, когато разбирате композитния модел и как можете да го внедрите, нека разгледаме пример за композитен шаблон с рамката Apache Struts JavaServer Pages (JSP).

Композитният модел и плочките на подпорите

Рамката Apache Struts включва библиотека с JSP тагове, известна като Tiles, която ви позволява да съставяте уеб страница от множество JSP. Tiles всъщност е изпълнение на модела J2EE (Java 2 Platform, Enterprise Edition) CompositeView, който се основава на композитния модел Design Patterns . Преди да обсъдим значението на композитния модел за библиотеката с етикети на плочки, нека първо разгледаме обосновката за плочки и как го използвате. Ако вече сте запознати с Struts Tiles, можете да прегледате следните раздели и да започнете да четете в „Използвайте композитния модел с Struts Tiles“.

Забележка: Можете да прочетете повече за модела J2EE CompositeView в моята статия „Компоненти на уеб приложенията, улеснени с композитен изглед“ ( JavaWorld, декември 2001 г.).

Дизайнерите често конструират уеб страници с набор от отделни региони; например, уеб страницата на Фигура 3 съдържа странична лента, заглавна част, регион на съдържанието и долен колонтитул.

Уебсайтовете често включват множество уеб страници с идентични оформления, като оформление на страничната лента / заглавката / съдържанието / долния колонтитул на Фигура 3. Struts Tiles ви позволява да използвате повторно съдържанието и оформлението между множество уеб страници. Преди да обсъдим това повторно използване, нека видим как оформлението на Фигура 3 традиционно се прилага само с HTML.

Прилагайте сложни оформления на ръка

Пример 1 показва как можете да приложите уеб страницата на Фигура 3 с HTML:

Пример 1. Сложно оформление, изпълнено на ръка

    Ръчно внедряване на сложни оформления <% - Една таблица излага цялото съдържание на тази страница -%>
   
Връзки

У дома

Продукти

Изтегляния

Бели книги

Свържете се с нас

Добре дошли в Sabreware, Inc.
Тук отива специфично за страниците съдържание

Благодаря, че се отбихте!

Предходният JSP има два основни недостатъка: Първо, съдържанието на страницата е вградено в JSP, така че не можете да използвате повторно нито едно от тях, въпреки че страничната лента, горният колонтитул и долният колонтитул вероятно са еднакви в много уеб страници. Второ, оформлението на страницата също е вградено в този JSP, така че вие ​​също не можете да го използвате повторно, въпреки че много други уеб страници в същия уебсайт използват същото оформление. Можем да използваме действието за отстраняване на първия недостатък, както обсъждам по-нататък.

Прилагане на сложни оформления с JSP включва

Пример 2 показва изпълнение на уеб страницата на Фигура 3, която използва :