תבנית עיצוב מבקרים בג'אווה

1. סקירה כללית

במדריך זה נציג את אחד מדפוסי העיצוב של GoF ההתנהגותי - ה- Visitor.

ראשית נסביר את מטרתה ואת הבעיה שהיא מנסה לפתור.

לאחר מכן, נסתכל על דיאגרמת ה- UML של Visitor והטמעת הדוגמה המעשית.

2. תבנית עיצוב מבקרים

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

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

כעת, כיצד נוכל להוסיף פונקציונליות חדשה לקוד שלנו ללא שינוי בכיתות הקיימות?

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

בצורה זו הרכיבים שלנו יאפשרו ליישום המבקרים "לבקר" אותם ולבצע כל פעולה נדרשת באלמנט זה.

במילים אחרות, נפיק מהמחלקות את האלגוריתם שיוחל על מבנה האובייקט.

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

3. דיאגרמת UML

בתרשים ה- UML לעיל, יש לנו שתי היררכיות יישום, מבקרים מיוחדים ואלמנטים קונקרטיים.

ראשית, הלקוח משתמש ביישום Visitor ומחיל אותו על מבנה האובייקט. האובייקט המרוכב מחרט על רכיביו ומחיל את המבקר על כל אחד מהם.

עכשיו, במיוחד זה רלוונטי אלמנטים קונקרטיים (ConcreteElement A. ו בטון אלמנט B) מקבלים א אורח, פשוט מאפשר זאת לְבַקֵר אוֹתָם.

לבסוף, שיטה זו זהה לכל האלמנטים במבנה, היא מבצעת משלוח כפול עם העברת עצמה (דרך ה- זֶה מילת מפתח) לשיטת הביקור של המבקר.

4. יישום

הדוגמה שלנו תהיה מנהגת מסמך אובייקט שמורכב מאלמנטים קונקרטיים של JSON ו- XML; לאלמנטים יש מעמד-על מופשט משותף, אֵלֵמֶנט.

ה מסמך מעמד:

מחלקה ציבורית מסמך מרחיב את האלמנט {רכיבי רשימה = ArrayList חדש (); // ... @ ביטול חלל ציבורי קבל (מבקר v) {עבור (אלמנט ה: this.elements) {e.accept (v); }}}

ה אֵלֵמֶנט בכיתה יש שיטה מופשטת המקבלת את אורח מִמְשָׁק:

תקציר ציבורי בטל (מבקר v);

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

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

המחלקה הציבורית JsonElement מרחיבה את האלמנט {// ... קבלת חלל ציבורי (Visitor v) {v.visit (this); }}

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

לכן, למבקר שלנו תהיה שיטה נפרדת לסוג הנתון:

מחלקה ציבורית ElementVisitor מיישמת Visitor {@Override public void visit (XmlElement xe) {System.out.println ("עיבוד אלמנט XML עם uuid:" + xe.uuid); } @ ביקור ריק ריק ציבורי (JsonElement je) {System.out.println ("עיבוד אלמנט JSON עם uuid:" + je.uuid); }}

כאן, המבקר הקונקרטי שלנו מיישם שתי שיטות, בהתאמה אחת לכל סוג של ה- אֵלֵמֶנט.

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

5. בדיקות

לצורך בדיקה, בואו נסתכל על VisitorDemoמעמד:

מעמד ציבורי VisitorDemo {main public public static public (String [] args) {Visitor v = new ElementVisitor (); מסמך d = מסמך חדש (createUuid ()); d.elements.add (JsonElement חדש (createUuid ())); d.elements.add (JsonElement חדש (createUuid ())); d.elements.add (XmlElement חדש (createUuid ())); ד.קבלה (v); } // ...}

ראשית, אנו יוצרים אֵלֵמֶנטמבקר, הוא מחזיק את האלגוריתם שנחיל על האלמנטים שלנו.

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

הפלט יהיה כך:

עיבוד אלמנט JSON עם uuid: fdbc75d0-5067-49df-9567-239f38f01b04 עיבוד אלמנט JSON עם uuid: 81e6c856-ddaf-43d5-aec5-8ef977d3745e עיבוד אלמנט XML עם uuid: 091bfcb8-2c68-203a-931

זה מראה שהמבקר ביקר בכל אלמנט במבנה שלנו, תלוי ב אֵלֵמֶנט סוג, הוא שלח את העיבוד לשיטה המתאימה ויכול לאחזר את הנתונים מכל אובייקט בסיסי.

6. חסרונות

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

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

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

7. מסקנה

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

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

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

כדי לראות גרסה מיוחדת יותר של דפוס העיצוב של Visitor, עיין בדפוס המבקרים ב- Java NIO - השימוש בתבנית ב- JDK.

כרגיל, הקוד השלם זמין בפרויקט Github.