JavaRush /בלוג Java /Random-HE /דפוסי עיצוב: סינגלטון

דפוסי עיצוב: סינגלטון

פורסם בקבוצה
שלום! היום נסתכל מקרוב על דפוסי עיצוב שונים, ונתחיל בדפוס הסינגלטון, הנקרא גם "סינגלטון". דפוסי עיצוב: סינגלטון - 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 Singleton INSTANCE;

  private Singleton() {}

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

מינוסים:
  • לא בטוח בשרשור

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

אביזר מסונכרן

public class Singleton {
  private static Singleton INSTANCE;

  private Singleton() {
  }

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

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

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

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

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

public class Singleton {
    private static 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חייב להיות או final, או volatile. היישום האחרון בו נדון היום הוא Class Holder Singleton.

מחזיק כיתה סינגלטון

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;
   }
}
יתרונות:
  • אתחול עצלן.

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

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

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

היישום כמעט מושלם. ועצלן, ובטוח חוט, ומהיר. אבל יש ניואנס המתואר במינוס. טבלת השוואה של יישומים שונים של דפוס הסינגלטון:
יישום אתחול עצלן בטיחות חוטים מהירות ריבוי השחלות מתי להשתמש?
פתרון פשוט - + מָהִיר לעולם לא. או כאשר אתחול עצלן אינו חשוב. אבל אף פעם לא טוב יותר.
אתחול עצלן + - לא ישים תמיד כאשר אין צורך בריבוי השחלות
אביזר מסונכרן + + לאט לעולם לא. או כאשר מהירות העבודה עם ריבוי השחלות לא משנה. אבל אף פעם לא טוב יותר
נעילה בבדיקה כפולה + + מָהִיר במקרים נדירים כאשר אתה צריך לטפל בחריגים בעת יצירת יחיד. (כאשר בעל המעמד Singleton אינו רלוונטי)
מחזיק כיתה סינגלטון + + מָהִיר תמיד כאשר יש צורך ב-multithreading ויש ערובה לכך שאובייקט מחלקה singleton ייווצר ללא בעיות.

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

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

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

עם זאת, לדפוס זה יש חסרונות:
  1. Singleton מפר את ה-SRP (Single Responsibility Principle) - מחלקת Singleton, בנוסף לאחריותה המיידית, שולטת גם במספר העותקים שלה.

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

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

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

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

קריאה נוספת:

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