CodeGym /בלוג Java /Random-HE /כיתת ג'אווה סינגלטון
John Squirrels
רָמָה
San Francisco

כיתת ג'אווה סינגלטון

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

מה זה סינגלטון בג'אווה?

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

  2. הוא מספק נקודת גישה גלובלית אחת לאותו מופע.

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

  2. שיטה סטטית ציבורית שמחזירה את המופע של המחלקה. שיטה זו נקראת getInstance . זוהי נקודת הגישה הגלובלית למופע המחלקה.

אפשרויות יישום

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

  • קוד פשוט ושקוף: המדד הזה, כמובן, הוא סובייקטיבי, אבל הוא חשוב.

  • בטיחות חוטים: פעולה נכונה בסביבה מרובת חוטים.

  • ביצועים גבוהים בסביבה מרובה הליכי: חסימת חוטים מועטה או ללא חסימת חוטים בעת שיתוף משאב.

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

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

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

  • ביצועים גרועים בסביבה מרובת חוטים: שרשורים חוסמים זה את זה כל הזמן או לעתים קרובות בעת שיתוף משאב.

קוד

כעת אנו מוכנים לשקול אפשרויות יישום שונות ולציין את היתרונות והחסרונות:

פָּשׁוּט

public class Singleton {
    private static final Singleton INSTANCE = new Singleton();

    private Singleton() {
    }

    public static Singleton getInstance() {
        return INSTANCE;
    }
}
היישום הפשוט ביותר. יתרונות:
  • קוד פשוט ושקוף

  • בטיחות חוטים

  • ביצועים גבוהים בסביבה מרובת חוטים

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

אתחול עצלן

public class Singleton {
  private static final Singleton INSTANCE;

  private Singleton() {}

  public static Singleton getInstance() {
    if (INSTANCE == null) {
      INSTANCE = new Singleton();
    }
    return INSTANCE;
  }
}
יתרונות:
  • אתחול עצלן.

חסרונות:
  • לא בטוח בשרשור

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

גישה מסונכרנת

public class Singleton {
  private static final Singleton INSTANCE;

  private Singleton() {
  }

  public static synchronized Singleton getInstance() {
    if (INSTANCE == null) {
      INSTANCE = new Singleton();
    }
    return INSTANCE;
  }
}
יתרונות:
  • אתחול עצלן.

  • בטיחות חוטים

חסרונות:
  • ביצועים גרועים עם ריבוי חוטים

מְעוּלֶה! ביישום מספר שלוש, אנו משחזרים את בטיחות השרשור! כמובן, זה איטי... כעת שיטת getInstance מסונכרנת, כך שניתן להפעיל אותה רק על ידי שרשור אחד בכל פעם. במקום לסנכרן את כל השיטה, אנחנו צריכים למעשה רק לסנכרן את החלק שלה שמאתחל את המופע החדש. אבל אנחנו לא יכולים פשוט להשתמש בבלוק מסונכרן כדי לעטוף את החלק שאחראי ליצירת המופע החדש. פעולה זו לא תבטיח את בטיחות החוטים. הכל קצת יותר מסובך. סנכרון נכון ניתן לראות להלן:

נעילה בבדיקה כפולה

public class Singleton {
    private static final Singleton INSTANCE;

  private Singleton() {
  }

    public static Singleton getInstance() {
        if (INSTANCE == null) {
            synchronized (Singleton.class) {
                if (INSTANCE == null) {
                    INSTANCE = new Singleton();
                }
            }
        }
        return INSTANCE;
    }
}
יתרונות:
  • אתחול עצלן.

  • בטיחות חוטים

  • ביצועים גבוהים בסביבה מרובת חוטים

חסרונות:
  • לא נתמך בגרסאות קודמות של Java מתחת ל-1.5 (השימוש במילת מפתח נדיפה קבוע מאז גרסת 1.5)

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

בעל כיתה

public class Singleton {

   private Singleton() {
   }

   private static class SingletonHolder {
       public static final Singleton HOLDER_INSTANCE = new Singleton();
   }

   public static Singleton getInstance() {
       return SingletonHolder.HOLDER_INSTANCE;
   }
}
יתרונות:
  • אתחול עצלן.

  • בטיחות חוטים.

  • ביצועים גבוהים בסביבה מרובת חוטים.

חסרונות:
  • פעולה נכונה דורשת ערובה לכך שאובייקט הסינגלטון מאותחל ללא שגיאות. אחרת, הקריאה הראשונה למתודה getInstance תגרום ל- ExceptionInInitializerError , וכל הקריאות הבאות יפיקו NoClassDefFoundError .

יישום זה כמעט מושלם. זה עצלן, ובטוח חוט, ומהיר. אבל יש לזה ניואנס, כפי שהוסבר ברשימת החסרונות. השוואה בין יישומים שונים של דפוס הסינגלטון:
יישום אתחול עצלן בטיחות חוטים ביצועים מרובים מתי להשתמש?
פָּשׁוּט - + מָהִיר לעולם לא. או אולי כאשר אתחול עצלן אינו חשוב. אבל לעולם לא יהיה טוב יותר.
אתחול עצלן + - לא ישים תמיד כאשר אין צורך בריבוי השחלות
גישה מסונכרנת + + לְהַאֵט לעולם לא. או אולי כאשר אין חשיבות לביצועים עם ריבוי חוטים. אבל לעולם לא יהיה טוב יותר.
נעילה בבדיקה כפולה + + מָהִיר במקרים נדירים כאשר אתה צריך לטפל בחריגים בעת יצירת הסינגלטון (כאשר הסינגלטון בעל הכיתה אינו ישים)
בעל כיתה + + מָהִיר בכל פעם שיש צורך בריבוי השחלות ויש ערובה שאובייקט הסינגלטון ייווצר ללא בעיות.

יתרונות וחסרונות של דפוס הסינגלטון

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

  2. הוא מספק נקודת גישה גלובלית אחת לאותו מופע.

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

  2. התלות של כיתה רגילה ביחיד לא נראית בחוזה הציבורי של הכיתה.

  3. משתנים גלובליים גרועים. בסופו של דבר, יחיד הופך למשתנה גלובלי כבד.

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

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

קריאה נוספת:

הערות
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION