JavaRush /مدونة جافا /Random-AR /أنماط التصميم: سينجلتون

أنماط التصميم: سينجلتون

نشرت في المجموعة
مرحبًا! اليوم سوف نلقي نظرة فاحصة على أنماط التصميم المختلفة، وسنبدأ بنمط المفرد، والذي يسمى أيضًا "المفرد". أنماط التصميم: مفردة - 1دعونا نتذكر: ماذا نعرف عن أنماط التصميم بشكل عام؟ تعد أنماط التصميم من أفضل الممارسات التي يمكن اتباعها لحل عدد من المشكلات المعروفة. لا ترتبط أنماط التصميم بشكل عام بأي لغة برمجة. خذها كمجموعة من التوصيات، والتي يمكنك من خلالها تجنب الأخطاء وعدم إعادة اختراع العجلة.

ما هو المفرد؟

يعد المفرد أحد أبسط أنماط التصميم التي يمكن تطبيقها على الفصل الدراسي. يقول الناس أحيانًا "هذه الفئة مفردة"، مما يعني أن هذه الفئة تطبق نمط التصميم المفرد. في بعض الأحيان يكون من الضروري كتابة فئة يمكن إنشاء كائن واحد فقط لها. على سبيل المثال، فئة مسؤولة عن التسجيل أو الاتصال بقاعدة بيانات. يصف نمط تصميم Singleton كيف يمكننا إنجاز مثل هذه المهمة. المفرد هو نمط تصميم يقوم بأمرين:
  1. يوفر ضمانًا بأن الفصل سيحتوي على مثيل واحد فقط من الفصل.

  2. يوفر نقطة وصول عالمية لمثيل هذه الفئة.

وبالتالي، هناك ميزتان مميزتان لكل تطبيق للنمط المفرد تقريبًا:
  1. منشئ خاص. يقيد القدرة على إنشاء كائنات فئة خارج الفئة نفسها.

  2. طريقة ثابتة عامة تقوم بإرجاع مثيل للفئة. هذه الطريقة تسمى getInstance. هذه هي نقطة الوصول العالمية إلى مثيل الفئة.

خيارات التنفيذ

يتم استخدام نمط التصميم المفرد بطرق مختلفة. كل خيار جيد وسيئ بطريقته الخاصة. هنا، كما هو الحال دائما: لا يوجد مثالي، ولكن عليك أن تسعى جاهدة لتحقيق ذلك. لكن أولاً، دعونا نحدد ما هو الجيد وما هو السيئ، وما هي المقاييس التي تؤثر على تقييم تنفيذ نمط التصميم. لنبدأ بالإيجابية. فيما يلي المعايير التي تعطي التنفيذ جاذبية وجاذبية:
  • التهيئة البطيئة: عندما يتم تحميل الفصل أثناء تشغيل التطبيق عند الحاجة إليه بالضبط.

  • بساطة وشفافية الكود: المقياس بالطبع ذاتي ولكنه مهم.

  • سلامة الخيط: يعمل بشكل صحيح في بيئة متعددة الخيوط.

  • أداء عالي في بيئة متعددة الخيوط: تحظر الخيوط بعضها البعض بشكل طفيف أو لا تحظرها على الإطلاق عند مشاركة المورد.

الآن السلبيات. دعونا ندرج المعايير التي تظهر التنفيذ في ضوء سيء:
  • التهيئة غير الكسولة: عندما يتم تحميل الفصل عند بدء تشغيل التطبيق، بغض النظر عما إذا كانت هناك حاجة إليه أم لا (مفارقة، في عالم تكنولوجيا المعلومات من الأفضل أن تكون كسولًا)

  • التعقيد وضعف إمكانية قراءة الكود. المقياس هو أيضا ذاتي. وسنفترض أنه إذا خرج الدم من العيون فإن التنفيذ يكون كذلك.

  • عدم سلامة الخيط. وبعبارة أخرى، "خطر الخيط". عملية غير صحيحة في بيئة متعددة الخيوط.

  • أداء ضعيف في بيئة متعددة الخيوط: تحظر سلاسل العمليات بعضها البعض طوال الوقت أو في كثير من الأحيان عند مشاركة المورد.

شفرة

نحن الآن على استعداد للنظر في خيارات التنفيذ المختلفة، مع ذكر الإيجابيات والسلبيات:

حل بسيط

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:
تطبيق التهيئة البطيئة سلامة الخيط سرعة تعدد الخيوط متى يجب استخدام؟
حل بسيط - + سريع أبداً. أو عندما لا تكون التهيئة البطيئة مهمة. ولكن أبدا أفضل.
التهيئة البطيئة + - غير قابل للتطبيق دائمًا عندما لا تكون هناك حاجة إلى تعدد العمليات
ملحق متزامن + + ببطء أبداً. أو عندما لا تكون سرعة العمل مع مؤشرات الترابط المتعددة مهمة. ولكن أبدا أفضل
قفل مزدوج التحقق + + سريع في حالات نادرة عندما تحتاج إلى التعامل مع الاستثناءات عند إنشاء مفردة. (عندما لا يكون الفصل المفرد لحامل الفئة قابلاً للتطبيق)
حامل الطبقة سينجلتون + + سريع دائمًا عندما تكون هناك حاجة إلى تعدد مؤشرات الترابط ويكون هناك ضمان بأنه سيتم إنشاء كائن فئة مفردة دون مشاكل.

إيجابيات وسلبيات نمط سينجلتون

بشكل عام، يقوم المفرد بالضبط بما هو متوقع منه:
  1. يوفر ضمانًا بأن الفصل سيحتوي على مثيل واحد فقط من الفصل.

  2. يوفر نقطة وصول عالمية لمثيل هذه الفئة.

ومع ذلك، فإن هذا النمط له عيوب:
  1. تنتهك Singleton SRP (مبدأ المسؤولية الفردية) - تتحكم فئة Singleton، بالإضافة إلى مسؤولياتها المباشرة، في عدد نسخها.

  2. إن اعتماد الفصل أو الطريقة العادية على المفردة غير مرئي في العقد العام للفئة.

  3. المتغيرات العالمية سيئة. يتحول المفرد في النهاية إلى متغير عالمي ضخم.

  4. يؤدي وجود المفرد إلى تقليل قابلية اختبار التطبيق بشكل عام والفئات التي تستخدم المفرد بشكل خاص.

حسنًا، لقد انتهى كل شيء الآن. نظرنا إلى نمط التصميم المفرد. الآن، في محادثة مدى الحياة مع أصدقائك المبرمجين، ستتمكن من قول ليس فقط ما هو جيد فيه، ولكن أيضًا بضع كلمات حول ما هو سيء فيه. حظا سعيدا في إتقان المعرفة الجديدة.

قراءة إضافية:

تعليقات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION