מבט על דפוס העיצוב המורכב

לפני כמה ימים האזנתי ל"שיחת המכוניות " של הרדיו הציבורי הלאומי , שידור שבועי פופולרי במהלכו המתקשרים שואלים שאלות על כלי הרכב שלהם. לפני כל הפסקת תוכנית, מארחי התוכנית מבקשים מהמתקשרים להתקשר למספר 1-800-CAR-TALK, המקביל למספר 1-800-227-8255. כמובן שהראשון מוכיח הרבה יותר קל לזכור מאשר האחרון, בין היתר משום שהמילים "CAR TALK" הן מורכבות: שתי מילים המייצגות שבע ספרות. לבני אדם בדרך כלל קל יותר להתמודד עם חומרים מרוכבים, ולא עם המרכיבים האישיים שלהם. כמו כן, כשאתה מפתח תוכנה מונחה עצמים, לעתים קרובות זה נוח לתפעל מרוכבים בדיוק כמו שאתה עושה מניפולציה על רכיבים בודדים. הנחת יסוד זו מייצגת את העיקרון הבסיסי של דפוס העיצוב המורכב,הנושא של דפוסי עיצוב Java אלה פֶּרֶק.

התבנית המורכבת

לפני שנצלול לתבנית המורכבת, עלי להגדיר תחילה אובייקטים מרוכבים: עצמים המכילים אובייקטים אחרים; לדוגמא, ציור עשוי להיות מורכב פרימיטיבים גרפיים, כגון קווים, עיגולים, מלבנים, טקסט וכו '.

מפתחי Java זקוקים לתבנית Composite מכיוון שלעיתים קרובות אנו חייבים לתמרן חומרים מרוכבים בדיוק באותו אופן שבו אנו מתפעלים עצמים פרימיטיביים. לדוגמא, יש לצייר, להזיז ולשנות את גודל הפרימיטיבים הגרפיים כמו שורות או טקסט. אך אנו רוצים לבצע את אותה פעולה גם על חומרים מרוכבים, כגון רישומים, המורכבים מאותם פרימיטיביים. באופן אידיאלי, נרצה לבצע פעולות הן על עצמים פרימיטיביים והן על חומרים מרוכבים בדיוק באותו אופן, מבלי להבחין בין השניים. אם עלינו להבחין בין אובייקטים פרימיטיביים למרכיבים כדי לבצע את אותן פעולות בשני סוגי האובייקטים, הקוד שלנו יהפוך מורכב יותר וקשה יותר ליישום, לתחזוקה ולהרחבה.

בשנת תבניות לעיצוב , המחברים מתארים את דפוס מרוכבים כמו זה:

חבר חפצים למבני עצים כדי לייצג היררכיות חלקיות שלמות. Composite מאפשר ללקוחות להתייחס לאובייקטים בודדים ולהרכבים של אובייקטים באופן אחיד.

יישום הדפוס המרוכב קל. מחלקות מורכבות מאריכות מחלקת בסיס המייצגת עצמים פרימיטיביים. איור 1 מציג תרשים כיתתי הממחיש את מבנה התבנית המורכבת.

בתרשים הכיתות של איור 1 השתמשתי בשמות כיתות מהדיון על תבנית מורכבת של תבנית העיצוב : Componentמייצג מחלקת בסיס (או אולי ממשק) עבור אובייקטים פרימיטיביים, Compositeומייצג מחלקה מורכבת. לדוגמה, Componentהמחלקה עשויה לייצג מחלקת בסיס לפרימיטיבים גרפיים, בעוד Compositeשהמחלקה עשויה לייצג Drawingמחלקה. Leafהמחלקה של איור 1 מייצגת אובייקט פרימיטיבי קונקרטי; למשל Lineכיתה או Textכיתה. Operation1()ואת Operation2()השיטות מייצגות שיטות תחום ספציפיות מיושמות על ידי השנייה Componentו Compositeכיתות.

Compositeהכיתה שומרת אוסף של רכיבים. בדרך כלל, Compositeהשיטות מיושמות על ידי איטרציה על פני אוסף זה והפעלת השיטה המתאימה לכל אחת Componentמהאוסף. לדוגמה, Drawingמחלקה עשויה ליישם את draw()השיטה שלה כך:

// שיטה זו הינה שיטת Composite public void draw () {// איטרציה מעל הרכיבים עבור (int i = 0; i <getComponentCount (); ++ i) {// השג התייחסות לרכיב והפעל את הציור שלו שיטה רכיב רכיב = ​​getComponent (i); component.draw (); }}

עבור כל שיטה המיושמת Componentבכיתה, Compositeהמחלקה מיישמת שיטה עם אותה חתימה המתחזרת על רכיבי המורכב, כפי שמודגם draw()בשיטה המפורטת לעיל.

Compositeבכיתה מרחיבה את Componentהמעמד, כך שתוכל לעבור מרוכבים לשיטה שצופה כי רכיב; לדוגמה, שקול את השיטה הבאה:

// שיטה זו מיושמת במחלקה שאינה קשורה למחלקות // Component ו- Composite לצביעה מחודשת של ריק (רכיב Component) {// הרכיב יכול להיות מורכב, אך מכיוון שהוא משתרע // המחלקה Component, אין צורך בשיטה זו // להבחין בין רכיבים למרכיבים component.draw (); }

השיטה הקודמת עוברת לרכיב - או רכיב פשוט או קומפוזיט - ואז היא קוראת draw()לשיטת אותו רכיב . מכיוון Compositeשהמחלקה מתרחבת Component, repaint()השיטה לא צריכה להבחין בין רכיבים למרכיבים - היא פשוט קוראת draw()לשיטה עבור הרכיב (או המורכב).

תרשים כיתת דפוס מורכב של איור 1 ממחיש בעיה אחת בתבנית: עליך להבחין בין רכיבים ומרכיבים כאשר אתה מתייחס לא ' Component, ועליך להפעיל שיטה ספציפית למורכב, כגון addComponent(). בדרך כלל אתה ממלא דרישה זו על ידי הוספת שיטה, למשל isComposite(), Componentלכיתה. שיטה זו חוזרת falseלרכיבים והיא נדרסת Compositeבכיתה להחזרה true. בנוסף, עליך גם להעביר את Componentההפניה Compositeלמופע, כך:

... אם (component.isComposite ()) {Composite composite = (Composite) רכיב; composite.addComponent (someComponentThatCouldBeAComposite); } ...

שימו לב addComponent()שהשיטה מועברת Componentכהפניה, שיכולה להיות מרכיב פרימיטיבי או מורכב. מכיוון שרכיב זה יכול להיות מרוכב, ניתן לחבר רכיבים למבנה עץ, כפי שמצוין בציטוט האמור מ- Patterns Design .

איור 2 מציג יישום חלופי של דפוס מורכב.

אם אתה מיישם את התבנית המורכבת של איור 2, אינך צריך להבחין בין רכיבים ומרכיבים לעולם, ואינך צריך להעביר Componentהפניה Compositeלמופע. אז קטע הקוד המופיע לעיל מצטמצם לשורה אחת:

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

אבל אם Componentההתייחסות בקטע הקוד הקודם לא מתייחסת ל- a Composite, מה addComponent()לעשות? זו נקודת מחלוקת עיקרית עם יישום הדפוס המורכב של איור 2. מכיוון שרכיבים פרימיטיביים אינם מכילים רכיבים אחרים, הוספת רכיב לרכיב אחר אינה הגיונית, ולכן Component.addComponent()השיטה יכולה להיכשל בשקט או לזרוק חריג. בדרך כלל, הוספת רכיב לרכיב פרימיטיבי אחר נחשבת לשגיאה, ולכן הטלת חריג היא אולי דרך הפעולה הטובה ביותר.

אז איזה יישום דפוס מורכב - זה שבאיור 1 או זה שבאיור 2 - עובד הכי טוב? זה תמיד נושא לוויכוח גדול בקרב מיישמי דפוס מורכב; דפוסי העיצוב מעדיפים את הטמעת איור 2 מכיוון שלעולם אינך צריך להבחין בין רכיבים למיכלים, ולעולם אינך צריך לבצע גבס. באופן אישי, אני מעדיף את היישום של איור 1, מכיוון שיש לי סלידה חזקה מיישום שיטות בכיתה שאינן הגיוניות לאותו סוג אובייקט.

כעת, לאחר שהבנתם את התבנית המורכבת וכיצד תוכלו ליישם אותה, בואו נבחן דוגמה לדפוס מורכב בעזרת מסגרת ה- Apache Struts JavaServer (JSP).

הדפוס המרוכב ואריחי תמוכות

מסגרת Apache Struts כוללת ספריית תג JSP, המכונה Tiles, המאפשרת לך להרכיב דף אינטרנט ממספר JSP. Tiles הוא למעשה יישום של דפוס ה- J2EE (Java 2 Platform, Enterprise Edition) CompositeView, עצמו המבוסס על דפוס ה- Compatible View של דפוסי העיצוב . לפני שנדון ברלוונטיות של התבנית המורכבת לספריית התגים אריחים, בואו נבדוק תחילה את הרציונל של אריחים וכיצד משתמשים בה. אם אתה כבר מכיר את אריחי Struts, אתה יכול לדלג על החלקים הבאים ולהתחיל לקרוא ב "השתמש בתבנית המורכבת עם אריחי Struts."

הערה: תוכלו לקרוא עוד על דפוס J2EE CompositeView במאמר "רכיבי יישום האינטרנט קלים עם תצוגה מורכבת" ( JavaWorld, דצמבר 2001).

מעצבים בונים לעתים קרובות דפי אינטרנט עם קבוצה של אזורים נפרדים; לדוגמא, דף האינטרנט של איור 3 כולל סרגל צד, כותרת, אזור תוכן וכותרת תחתונה.

אתרים כוללים לרוב דפי אינטרנט מרובים עם פריסות זהות, כגון פריסת הצד / כותרת / תוכן / כותרת תחתונה של איור 3. Struts Tiles מאפשר לך לעשות שימוש חוזר הן בתוכן והן בפריסה בין דפי אינטרנט מרובים. לפני שנדון בשימוש חוזר זה, בואו נראה כיצד הפריסה של איור 3 מיושמת באופן מסורתי עם HTML בלבד.

יישם פריסות מורכבות ביד

דוגמה 1 מראה כיצד ניתן ליישם את דף האינטרנט של איור 3 באמצעות HTML:

דוגמא 1. פריסה מורכבת המיושמת ביד

    יישום פריסות מורכבות ביד <% - טבלה אחת מציגה את כל התוכן של דף זה -%>
   
קישורים

בית

מוצרים

הורדות

ניירות לבנים

צור קשר

ברוך הבא ל- Sabreware, Inc.
כאן מופיע תוכן ספציפי לדף

תודה שקפצת לבקר!

ל- JSP הקודם יש שני חסרונות עיקריים: ראשית, תוכן העמוד מוטבע ב- JSP, כך שלא תוכל לעשות שימוש חוזר בכל אחד מהם, למרות שסרגל הצד, הכותרת התחתונה וכותרת התחתונה עשויים להיות זהים בכל דפי אינטרנט רבים. שנית, פריסת העמוד מוטמעת גם באותה JSP, כך שגם אינך יכול לעשות בה שימוש חוזר למרות שדפי אינטרנט רבים אחרים באותו אתר משתמשים באותה פריסה. אנו יכולים להשתמש בפעולה כדי לתקן את החיסרון הראשון, כפי שאדון בהמשך.

יישום פריסות מורכבות עם JSP כולל

דוגמה 2 מציגה יישום של דף האינטרנט של איור 3 המשתמש בה :