יחידים בג'אווה

1. הקדמה

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

2. סינגלטון מבוסס כיתות

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

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

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

מחלקה סופית ציבורית ClassSingleton {ClassSingleton פרטי סטטי פרטי; פרטי מחרוזת פרטי = "מחלקת מידע ראשונית"; ClassSingleton פרטי () {} ClassSingleton סטטי ציבורי getInstance () {if (INSTANCE == null) {INSTANCE = ClassSingleton חדש (); } להחזיר INSTANCE; } // גטרים וקובעים}

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

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

3. אנום סינגלטון

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

EnumSingleton {INSTANCE ("מידע ראשוני בכיתה"); פרטי מחרוזת פרטיים; פרטי EnumSingleton (מידע על מחרוזות) {this.info = מידע; } EnumSingleton הציבורית getInstance () {return INSTANCE; } // גטרים וקובעים}

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

4. שימוש

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

ClassSingleton classSingleton1 = ClassSingleton.getInstance (); System.out.println (classSingleton1.getInfo ()); // מידע ראשוני בכיתה ClassSingleton classSingleton2 = ClassSingleton.getInstance (); classSingleton2.setInfo ("מידע כיתתי חדש"); System.out.println (classSingleton1.getInfo ()); // מידע כיתתי חדש System.out.println (classSingleton2.getInfo ()); // מידע כיתתי חדש

בנוגע ל EnumSingletonאנו יכולים להשתמש בו כמו בכל Java Enum אחר:

EnumSingleton enumSingleton1 = EnumSingleton.INSTANCE.getInstance (); System.out.println (enumSingleton1.getInfo ()); // מידע ראשוני על enum EnumSingleton enumSingleton2 = EnumSingleton.INSTANCE.getInstance (); enumSingleton2.setInfo ("מידע חדש על enum"); System.out.println (enumSingleton1.getInfo ()); // מידע חדש על Enum System.out.println (enumSingleton2.getInfo ()); // מידע חדש על enum

5. מלכודות נפוצות

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

אנו מבחינים בשני סוגים של נושאים עם יחידים:

  • קיומי (האם אנו זקוקים ליחיד?)
  • יישומי (האם אנו מיישמים אותו כמו שצריך?)

5.1. סוגיות קיומיות

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

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

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

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

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

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

5.2. סוגיות יישום

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

סִנכְּרוּן

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

ClassSingleton סטטי מסונכרן ציבורי getInstance () {if (INSTANCE == null) {INSTANCE = ClassSingleton חדש (); } להחזיר INSTANCE; }

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

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

סִנכְּרוּן עשוי להשפיע באופן משמעותי על הביצועים. אם קוד זה מופעל לעיתים קרובות, עלינו לזרז אותו באמצעות טכניקות שונות כמו אתחול עצלן אוֹ נעילה מבוקרת פעמיים (שים לב שייתכן שזה לא יעבוד כצפוי עקב אופטימיזציות של מהדר). אנו יכולים לראות פרטים נוספים במדריך שלנו "נעילה כפולה עם סינגלטון".

מקרים מרובים

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

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

6. מסקנה

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

ניתן למצוא את היישום המלא של דוגמאות אלה ב- GitHub.