design-patterns - شرح - singleton معنى




الفرق بين الطبقة الثابتة ونمط المفرد؟ (20)

ما الفرق الحقيقي (أي العملي) بين الطبقة الثابتة ونمط المفرد؟

يمكن استدعاء كلاهما دون إنشاء مثيل ، وكلاهما يوفر "مثيل" واحد فقط ولا يكون أي منهما آمنًا. هل هناك أي اختلاف آخر؟


  1. تحميل كسول
  2. دعم واجهات ، بحيث يمكن توفير التنفيذ المنفصل
  3. القدرة على إرجاع نوع مشتق (كمزيج من lazyloading وتطبيق واجهة)

  1. يتم تخزين الكائنات سينجليتون في كومة الذاكرة المؤقتة ولكن يتم تخزين كائنات ثابتة في مكدس .
  2. يمكننا استنساخ (إذا كان المصمم لا يمنع ذلك) الكائن المفرد ، ولكن لا يمكننا استنساخ كائن الفئة الثابت.
  3. تتبع الفئات Singleton OOP (مبادئ موجهة إلى الكائنات) ، والفئات الثابتة لا.
  4. يمكننا تنفيذ interface مع فئة Singleton ، ولكن الأساليب الثابتة للصف (أو على سبيل المثال فئة C # static class ) لا يمكن.

Singleton هو نهج أفضل من منظور الاختبار. على عكس الطبقات الثابتة ، يمكن أن تقوم المفردات بتنفيذ واجهات ، ويمكنك استخدام أمثلة وهمية وحقنها.

في المثال أدناه ، سأوضح ذلك. لنفترض أن لديك طريقة هي GoodPrice () التي تستخدم getPrice () وتقوم بتنفيذ getPrice () كطريقة في singleton.

المفرد الذي يوفر وظيفة getPrice:

public class SupportedVersionSingelton {

    private static ICalculator instance = null;

    private SupportedVersionSingelton(){

    }

    public static ICalculator getInstance(){
        if(instance == null){
            instance = new SupportedVersionSingelton();
        }

        return instance;
    }

    @Override
    public int getPrice() {
        // calculate price logic here
        return 0;
    }
}

استخدام getPrice:

public class Advisor {

    public boolean isGoodDeal(){

        boolean isGoodDeal = false;
        ICalculator supportedVersion = SupportedVersionSingelton.getInstance();
        int price = supportedVersion.getPrice();

        // logic to determine if price is a good deal.
        if(price < 5){
            isGoodDeal = true;
        }

        return isGoodDeal;
    }
}


In case you would like to test the method isGoodPrice , with mocking the getPrice() method you could do it by:
Make your singleton implement an interface and inject it. 



  public interface ICalculator {
        int getPrice();
    }

تنفيذ سينجلتون النهائي:

public class SupportedVersionSingelton implements ICalculator {

    private static ICalculator instance = null;

    private SupportedVersionSingelton(){

    }

    public static ICalculator getInstance(){
        if(instance == null){
            instance = new SupportedVersionSingelton();
        }

        return instance;
    }

    @Override
    public int getPrice() {
        return 0;
    }

    // for testing purpose
    public static void setInstance(ICalculator mockObject){
        if(instance != null ){
instance = mockObject;
    }

فئة الاختبار:

public class TestCalculation {

    class SupportedVersionDouble implements ICalculator{
        @Override
        public int getPrice() { 
            return 1;
        }   
    }
    @Before
    public void setUp() throws Exception {
        ICalculator supportedVersionDouble = new SupportedVersionDouble();
        SupportedVersionSingelton.setInstance(supportedVersionDouble);

    }

    @Test
    public void test() {
          Advisor advidor = new Advisor();
          boolean isGoodDeal = advidor.isGoodDeal();
          Assert.assertEquals(isGoodDeal, true);

    }

}

في حال أخذنا بديل استخدام طريقة ثابتة لتنفيذ getPrice () ، فقد كان من الصعب أن getPrice (). يمكنك الاستهزاء بالقدرة الثابتة ، ولكن ليس كل المنتجات يمكن استخدامها.


أنا أوافق على هذا التعريف:

تعني كلمة " مفرد " كائنًا واحدًا عبر دورة حياة التطبيق ، لذلك يكون النطاق عند مستوى التطبيق.

لا يحتوي static على أي مؤشر كائن ، لذلك يكون النطاق في مستوى مجال التطبيق.

وعلاوة على ذلك يجب تنفيذ كلاهما ليكون خيط آمن.

يمكنك أن تجد اختلافات مفيدة أخرى حول: Singleton Pattern Versus Static Class


إليك مقالة جيدة: http://javarevisited.blogspot.com.au/2013/03/difference-between-singleton-pattern-vs-static-class-java.html

فئات ثابتة

  • فئة لديها كل الأساليب الثابتة .
  • أداء أفضل (يتم ربط الطرق الثابتة في وقت التحويل البرمجي)
  • لا يمكن تجاوز الأساليب ، ولكن يمكن استخدام إخفاء الطريقة. ( ما هي الطريقة التي يختبئ بها جافا؟ حتى أن تفسير JavaDoc مربك )

    public class Animal {
        public static void foo() {
            System.out.println("Animal");
        }
    }
    
    public class Cat extends Animal {
        public static void foo() {  // hides Animal.foo()
            System.out.println("Cat");
        }
    }
    

الورقة المفردة

باختصار ، أود فقط استخدام الفصول الثابتة لعقد طرق الاستخدام ، واستخدام Singleton لكل شيء آخر.

التعديلات


ا. التسلسل - ينتمي أعضاء ثابتون إلى الفصل ومن ثم لا يمكن إجراء تسلسل.

ب. على الرغم من أننا جعلنا المنشئ خاصا ، إلا أن المتغيرات الخاصة بالأعضاء الثابتة ستظل محمولة إلى فئة فرعية.

ج. لا يمكننا إجراء التهيئة البطيئة حيث سيتم تحميل كل شيء عند تحميل الفصل فقط.


الجواب الحقيقي هو جون سكيت ، في منتدى آخر هنا .

يتيح المفرد الوصول إلى مثيل واحد تم إنشاؤه - يمكن تمرير ذلك المثيل (أو بالأحرى إشارة إلى ذلك المثال) كمعلمة إلى طرق أخرى ، ويتم التعامل معه ككائن عادي.

تسمح فئة ثابتة بالطرق الثابتة فقط.


حسناً ، إن singleton هو مجرد فئة عادية يتم تحديثها ، ولكن مرة واحدة وبشكل غير مباشر من رمز العميل. لا يتم إنشاء مثيل للطبقة الثابتة. بقدر ما أعرف أساليب ثابتة (يجب أن يكون لديك فئة ثابتة أساليب ثابتة) هي أسرع من غير ثابتة.

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


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

أود أن أقول أن أكبر الفرق هو أن singleton لا يزال Java Bean عادي كما يعارض لفئة Java خاصة ثابتة فقط. وبسبب هذا ، يتم قبول مفردة في العديد من الحالات ؛ هو في الواقع استراتيجية إنشاء الإطار الافتراضي لـ Spring Framework. قد يعرف أو لا يعرف المستهلك أنه تم تمريره منفردة ، فقط يعامله مثل حبة جافا الطبيعية. إذا تغيرت المتطلبات وتحتاج المفردات إلى أن تصبح نموذجًا أوليًا ، كما نلاحظ في الربيع ، يمكن أن يتم ذلك بشكل سلس بدون وجود تغيير في التعليمات البرمجية للمستهلك.

وقد ذكر شخص آخر في وقت سابق أن فئة ثابتة ينبغي أن تكون إجرائية بحتة مثل java.lang.Math. في رأيي ، يجب عدم تمرير مثل هذه الفئة مطلقًا ، ولا ينبغي لها أبدًا الاحتفاظ بأي شيء آخر غير نهائي ثابت كسمات. لكل شيء آخر ، استخدم singleton لأنه أكثر مرونة وسهولة في الصيانة.


في مقال كتبته وصفت وجهة نظري حول السبب في أن المفرد أفضل بكثير من طبقة ثابتة:

  1. الطبقة الثابتة ليست في الواقع فئة أساسية - إنها مساحة اسم ذات وظائف ومتغيرات
  2. لا يعد استخدام فئة ثابتة ممارسة جيدة بسبب كسر مبادئ البرمجة الشيئية
  3. لا يمكن تمرير فئة ثابتة كمعلمة من أجل أخرى
  4. الطبقة الثابتة غير مناسبة للتهيئة "البطيئة"
  5. دائمًا ما يكون من الصعب تعقب التهيئة واستخدام فئة ثابتة
  6. تنفيذ إدارة الصفحات صعبة

قرأت ما يلي وأعتقد أنه من المنطقي أيضًا:

رعاية الأعمال

تذكر أن أحد أهم قواعد OO هو أن الكائن مسؤول عن نفسه. وهذا يعني أنه ينبغي التعامل مع القضايا المتعلقة بدورة حياة الفصل الدراسي في الفصل الدراسي ، وليس تفويضًا إلى بنى لغوية مثل ثابت ، وهكذا.

من كتاب "الفكر المنحى المنحى عملية" 4 إد.


لا ينبغي للفصول static أن تفعل أي شيء تحتاج إلى حالة ، فهي مفيدة لوضع مجموعة من الوظائف معاً مثل Math (أو Utils في المشاريع). لذا ، فإن اسم الصف يعطينا فكرة حيث يمكننا العثور على الوظائف وليس هناك المزيد.

Singleton هو النمط المفضل لدي ، واستخدمه لإدارة شيء ما في نقطة واحدة. إنها أكثر مرونة من الطبقات static ويمكن أن تحافظ على الدولة. يمكنه تنفيذ الواجهات ، ويرث من الطبقات الأخرى ويسمح بالميراث.

قاعدتي للاختيار بين static singleton :

إذا كان هناك حفنة من الوظائف يجب أن تبقى مع بعضها البعض ، فإن static هو الخيار. أي شيء آخر يحتاج إلى وصول واحد إلى بعض الموارد ، يمكن تنفيذه singleton .


لدينا إطار عمل DB الذي يقوم بإجراء اتصالات إلى النهاية الخلفية. لتجنب القراءات القذرة عبر مستخدمين متعددين استخدمنا نمط singleton لضمان توفر مثيل واحد متوفر في أي وقت.

في c # لا يمكن لفئة ثابتة تنفيذ واجهة. عندما تحتاج فئة مثيل واحدة إلى تطبيق واجهة لعقود العمل أو أغراض IoC ، فهذا هو المكان الذي أستخدم فيه نمط Singleton بدون فصل ثابت

يوفر Singleton طريقة للحفاظ على الحالة في سيناريوهات عديم الحالة

نأمل أن يساعدك ..


للتوسع في جواب Jon Skeet

والفارق الكبير بين المفرد وحزمة من الأساليب الثابتة هو أن المفردات يمكن أن تنفذ واجهات (أو تنبع من الطبقات الأساسية المفيدة ، على الرغم من أن هذا أقل من IME) ، بحيث يمكنك المرور حول المفرد كما لو كان تطبيق "مجرد آخر".

تعتبر Singletons أسهل في العمل عند اختبار الوحدة للفئة. فأينما تقوم بتمرير مفردات كمعلمة (منشئات أو مستوطنين أو أساليب) ، فيمكنك بدلاً من ذلك استبدال نسخة مستهزئة أو موصولة من المفرد.


من منظور العميل ، يُعرف السلوك الثابت للعميل ولكن يمكن إتمام سلوك Singleton مخفيًا من عميل. قد لا يعرف العميل أبداً أنه يوجد مثيل واحد فقط يلعب معه مراراً وتكراراً.


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


يتم إنشاء مثيل سينجليتون ، فقط هناك مثيل واحد من أي وقت مضى إنشاء مثيل ، وبالتالي واحدة في سينجلتون.

لا يمكن إنشاء فئة ثابتة بواسطة أي شيء آخر غير نفسه.


فئة ثابتة: -

  1. لا يمكنك إنشاء مثيل لفئة ثابتة.

  2. يتم تحميله تلقائيًا من خلال وقت تشغيل NET Framework العام (CLR) عندما يتم تحميل البرنامج أو مساحة الاسم التي تحتوي على الفئة.

  3. فئة ثابتة لا يمكن أن يكون منشئ.

  4. لا يمكننا تمرير الطبقة الثابتة إلى الطريقة.

  5. لا يمكننا ترميز فئة ثابتة إلى فئة ثابتة أخرى في C #.

  6. فئة تحتوي على جميع الأساليب الثابتة.

  7. أداء أفضل (يتم ربط الطرق الثابتة في وقت التحويل البرمجي)

المفرد: -

  1. يمكنك إنشاء مثيل واحد للكائن وإعادة استخدامه.

  2. يتم إنشاء مثيل سينجلتون لأول مرة عندما يطلب المستخدم.

  3. يمكن أن يكون لفئة سينجلتون منشئ.

  4. يمكنك إنشاء كائن فئة singleton وتمريرها إلى الطريقة.

  5. لا يقول صنف سينجلتون أي قيود على الميراث.

  6. يمكننا التخلص من الكائنات من فئة singleton ولكن ليس من فئة ثابتة.

  7. يمكن تجاوز الطرق.

  8. يمكن أن يكون كسول تحميل عند الحاجة (يتم دائماً تحميل فئات ثابتة).

  9. يمكننا تنفيذ واجهة (فئة ثابتة لا يمكن تنفيذ واجهة).


There is a huge difference between a single static class instance (that is, a single instance of a class, which happens to be a static or global variable) and a single static pointer to an instance of the class on the heap:

When your application exits, the destructor of the static class instance will be called. That means if you used that static instance as a singleton, your singleton ceased working properly. If there is still code running that uses that singleton, for example in a different thread, that code is likely to crash.


When I want class with full functionality, eg there are many methods and variables, I use singleton;

If I want class with only one or two methods in it, eg MailService class, which has only 1 method SendMail() I use static class and method.





singleton