Smart-World Surf

יחידה 10: דפוסי תכנון ונושאים מתקדמים

עקרונות תכנון מתקדמים וכלים שימושיים לפיתוח תוכנה.
דפוסי תכנון (SingletonObserver)Javadoc לתיעוד קודביטוי למדא (Lambda Expressions)UML

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

דפוסי תכנון (Design Patterns)

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

דפוס Singleton

Singleton: דפוס תכנון מבני המבטיח שקיימת רק מופע (instance) אחד של מחלקה מסוימת, ומספק נקודת גישה גלובלית יחידה למופע זה.
  • מטרה: שליטה על יצירת אובייקטים כך שרק אובייקט אחד מסוג מסוים יוכל להתקיים במערכת. שימושי למשל עבור מנהלי קונפיגורציה, מאגרי חיבורים (connection pools) או לוגרים.
  • יישום:
    • קונסטרוקטור פרטי (private constructor) כדי למנוע יצירת מופעים מבחוץ.
    • שדה סטטי פרטי (private static field) להחזקת המופע היחיד של המחלקה.
    • שיטה סטטית ציבורית (public static method), לרוב בשם getInstance(), המספקת גישה למופע. שיטה זו יוצרת את המופע בפעם הראשונה שקוראים לה (lazy initialization).

דפוס Observer

Observer: דפוס תכנון התנהגותי המגדיר תלות של אחד לרבים בין אובייקטים, כך שכאשר אובייקט אחד משנה את מצבו, כל תלויותיו מקבלות הודעה ומתעדכנות אוטומטית.
  • מטרה: לאפשר לאובייקטים (Observers) להירשם לקבלת עדכונים מאובייקט אחר (Subject/Observable) מבלי שה-Subject יצטרך לדעת דבר על ה-Observers הספציפיים. מקדם צימוד רפוי (loose coupling).
  • רכיבים עיקריים:
    • Subject (או Observable): האובייקט שמצבו משתנה. הוא מכיל רשימה של Observers, שיטות לרישום (registerObserver()), ביטול רישום (unregisterObserver()) ועדכון (notifyObservers()).
    • Observer: הממשק או המחלקה המופשטת שמגדירה שיטת עדכון (לרוב update()) שה-Subject יקרא לה.
    • Concrete Subject: מימוש ספציפי של ה-Subject.
    • Concrete Observer: מימוש ספציפי של ה-Observer.

Singleton

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

Observer

מגדיר תלות של אחד לרבים לעדכון אוטומטי. שימושי למערכות מונעות אירועים (event-driven).

דפוס Singleton - יתרונות וחסרונות: דפוס Singleton נחשב לפעמים ל"אנטי-דפוס" בשל חסרונותיו. בעוד שהוא מבטיח מופע יחיד וחוסך משאבים, הוא עלול לפגוע ביכולת הבדיקה (testability) של הקוד מכיוון שהוא יוצר תלות גלובלית קשיחה, מקשה על בידוד רכיבים לבדיקות יחידה, ועלול להוביל לבעיות ביישומים מרובי-תהליכים (multi-threaded) אם לא מיושם נכון (למשל, בעיות סנכרון). חשוב לשקול היטב את הצורך בו וליישם אותו בזהירות.

תיעוד קוד עם Javadoc

תיעוד קוד איכותי הוא קריטי להבנה, תחזוקה ושיתוף פעולה בפרויקטי תוכנה. Javadoc הוא כלי סטנדרטי ב-Java ליצירת תיעוד API אוטומטי ישירות מהערות בקוד המקור.

Javadoc: כלי מובנה ב-Java המאפשר יצירת תיעוד HTML מקצועי עבור מחלקות, ממשקים, שדות ומתודות, באמצעות הערות מיוחדות בקוד המקור.
  • חשיבות:
    • מקל על הבנת הקוד עבור מפתחים אחרים (ועבורכם בעתיד).
    • משמש כתיעוד רשמי של ה-API של הספריה או המודול.
    • משפר את איכות התוכנה ומפחית טעויות.
  • תגי Javadoc נפוצים:
    • @param <name> <description>: מתאר פרמטר של מתודה.
    • @return <description>: מתאר את הערך המוחזר על ידי מתודה.
    • @throws <class-name> <description>: מתאר חריגה (exception) שמתודה עשויה לזרוק.
    • @see <reference>: מפנה למחלקה, מתודה או URL קשורים.
    • @author <name>: מציין את מחבר הקוד.
    • @version <version-text>: מציין את גרסת הקוד.
  • כתיבת הערות Javadoc: הערות Javadoc מתחילות ב-/** ומסתיימות ב-*/. הן צריכות להיות תמציתיות, ברורות ולתאר את ה"מה" ולא את ה"איך" של הקוד.

ביטויי למדא (Lambda Expressions)

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

ביטוי למדא: פונקציה אנונימית (ללא שם) שניתן להעביר כארגומנט למתודות או לאחסן במשתנים. מאפשר כתיבת קוד קצר יותר וקריא יותר עבור ממשקים פונקציונליים.
  • מבנה בסיסי: (parameters) -> expression או (parameters) -> { statements; }.
  • ממשקים פונקציונליים (Functional Interfaces): ביטויי למדא יכולים לשמש רק במקומות שבהם מצופה ממשק פונקציונלי. ממשק פונקציונלי הוא כל ממשק שמכיל שיטה מופשטת אחת בלבד (Single Abstract Method - SAM). דוגמאות: Runnable, Comparator, ActionListener.
  • יתרונות:
    • קוד קצר יותר: מפחית את הצורך במחלקות אנונימיות פנימיות.
    • קריאות משופרת: קל יותר להבין את מטרת הקוד.
    • תכנות פונקציונלי: מאפשר שימוש בזרמים (Streams) ובפעולות פונקציונליות על אוספים.
  • דוגמה: במקום:
    Collections.sort(list, new Comparator<String>() {
        @Override
        public int compare(String s1, String s2) {
            return s1.compareTo(s2);
        }
    });
    ניתן לכתוב:
    Collections.sort(list, (s1, s2) -> s1.compareTo(s2));

UML (Unified Modeling Language)

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

UML: שפת מידול גרפית סטנדרטית בתעשיית התוכנה, המשמשת לתיאור חזותי של ארכיטקטורת מערכות תוכנה, התנהגותן ומבנה הנתונים שלהן.
  • חשיבות:
    • תקשורת: מספק שפה משותפת למפתחים, אנליסטים ולקוחות.
    • תכנון: מסייע בתכנון המערכת לפני כתיבת קוד.
    • תיעוד: משמש כתיעוד חזותי של המערכת.
  • דיאגרמות נפוצות:
    • דיאגרמת מחלקות (Class Diagram)

      • מטרה: מתארת את המבנה הסטטי של המערכת במונחים של מחלקות, התכונות (attributes) והפעולות (methods) שלהן, והקשרים ביניהן (אסוציאציה, אגרגציה, קומפוזיציה, ירושה, מימוש).
      • רכיבים: מחלקות (מלבנים עם 3 חלקים: שם, תכונות, פעולות), קשרים (קווים עם סמלים שונים).
    • דיאגרמת רצף (Sequence Diagram)

      • מטרה: מתארת את האינטראקציה הדינמית בין אובייקטים במערכת לאורך זמן, תוך התמקדות בסדר ההודעות (messages) המועברות ביניהם.
      • רכיבים: קווי חיים (lifelines) המייצגים אובייקטים, מלבני הפעלה (activation bars) המציינים תקופות פעילות, וחצים המייצגים הודעות.

שאלות לדיון

  • כיצד דפוסי תכנון תורמים ליכולת התחזוקה וההרחבה של מערכות תוכנה?
  • השוו והנגידו בין דפוס Singleton לדפוס Observer, והציגו תרחיש מתאים לשימוש בכל אחד מהם.
  • הסבירו כיצד ביטויי למדא משפרים את קריאות הקוד וקיצורו ב-Java, והדגימו זאת באמצעות דוגמה.
  • תארו את תפקידו של Javadoc בסביבת פיתוח תוכנה מקצועית, וציינו לפחות שלושה תגים נפוצים.
  • כיצד דיאגרמות מחלקות ודיאגרמות רצף ב-UML משלימות זו את זו בתיעוד עיצוב המערכת?

נקודות לתשובת מודל

  • דפוסי תכנון: פתרונות מוכחים לבעיות נפוצות, מקדמים שימוש חוזר, מודולריות, צימוד רפוי.
  • Singleton vs. Observer:
    • Singleton: מבני, מופע יחיד, גישה גלובלית (למשל, מנהל לוגים).
    • Observer: התנהגותי, אחד-לרבים, עדכון אוטומטי (למשל, עדכון UI מנתונים).
  • ביטויי למדא: פונקציות אנונימיות, (params) -> body, ממשקים פונקציונליים, קוד קצר וקריא יותר, תכנות פונקציונלי (למשל, מיון או סינון אוספים).
  • Javadoc: כלי לתיעוד API אוטומטי, משפר תקשורת, הבנה ותחזוקה. תגים: @param, @return, @throws, @see.
  • UML:
    • דיאגרמת מחלקות: מבנה סטטי (מחלקות, תכונות, פעולות, קשרים).
    • דיאגרמת רצף: התנהגות דינמית (אינטראקציות אובייקטים, סדר הודעות).
    • השלמה: מחלקות מציגות את ה"מי" וה"מה", רצף מציג את ה"איך" וה"מתי" של האינטראקציות.
מצאתם טעות או שחסר משהו?
→ הקודמת
תכנות רשת