1. ما هو نمط التصميم
في هندسة البرمجيات ، يعد نمط التصميم حلًا مقترحًا لمشكلات مختلفة (متكررة) مشتركة في تصميم البرامج. تم تقديم هذا المصطلح في علوم الكمبيوتر من مجال التصميم المعماري في التسعينيات من قبل إريك جاما وغيرهم.
عصابة شهيرة من 4 أشخاص: إريك جاما ، ريتشارد هيلم ، رالف جونسون ، جون فليسيدس (GOF)
نمط التصميم: أساسيات البرمجيات الموجهة للكائنات القابلة لإعادة الاستخدام
2. وضع Singleton
يجب ضمان وجود فئة من كائن Singleton لوجود مثيل واحد فقط. في كثير من الأحيان ، لا يحتاج النظام بأكمله إلا إلى الحصول على كائن عالمي واحد ، والذي يفضي إلى تنسيقنا للسلوك العام للنظام.
على سبيل المثال: تكوين المعلومات العالمية
أبسط تطبيق لوضع سينجلتون:
الطبقة العامة Singleton {private Singleton () {system.out.println ("Singleton is Create") ؛ } مثيل خاص ثابت Singleton = New Singleton () ؛ Singleton Singleton GetInstance () {return مثيل ؛ }} يتم تحديد التفرد من قبل المنشئ الخاص وثابت.
العيوب: عندما يتم إنشاء مثيل يصعب التحكم فيه
على الرغم من أننا نعلم أنه عندما يتم تحميل Singleton الفصل لأول مرة ، يتم إنشاء مثيل.
ولكن إذا كانت هناك خصائص أخرى في هذا الفصل
الطبقة العامة Singleton {public static int status = 1 ؛ خاص singleton () {system.out.println ("Singleton Is Create") ؛ } مثيل خاص ثابت Singleton = New Singleton () ؛ Singleton Singleton GetInstance () {return مثيل ؛ }} عند استخدام
System.out.println (Singleton.Status) ؛
يتم إنتاج هذا المثال. ربما لا تريد إنشاء هذه الحالة في هذا الوقت.
إذا كان النظام يولي اهتمامًا خاصًا لهذه المشكلة ، فإن طريقة التنفيذ لهذا المفرد ليست جيدة جدًا.
الحل لوضع المفرد الثاني:
الطبقة العامة Singleton {private Singleton () {system.out.println ("Singleton is Create") ؛ } مثيل Singleton الثابت الخاص = NULL ؛ مثيل Singleton GetInstance () {if (مثيل == null) = New Singleton () ؛ مثيل العودة ؛ }} Let Let Onder Lean فقط عند استدعاء طريقة getInstance () ، ويتم ضمان سلامة الخيط من خلال المزامنة.
هذه الضوابط عند إنشاء الحالات.
هذا النهج نموذجي من التحميل كسول.
لكن إحدى المشكلات هي أن الأداء سيكون له تأثير في سيناريوهات التزامن العالية. على الرغم من أنه يتم إرجاعه بحكم واحد فقط ، إلا أنه سيكون له تأثير في حالة التزامن العالي ، إلا أنه سيكون له تأثير أكثر أو أقل لأنه يتعين عليك الحصول على القفل المتزامن.
لكي تكون فعالة ، هناك طريقة ثالثة:
الطبقة العامة staticsingleton {private staticsingleton () {system.out.println ("Staticsingleton is create") ؛ } static static static singletonholder {private static staticsingleton مثيل = جديد staticsingleton () ؛ } staticsingleton getInstance () {return singletonholder.instance ؛ }} نظرًا لأنه عندما يتم تحميل الفصل ، فلن يتم تحميل فئته الداخلية. هذا يضمن أن يتم إنشاء المثيل فقط عند استدعاء getInstance () ، ويتم التحكم في وقت توليد المثيل ، ويتم تحقيق تأخير التحميل.
وتتم إزالة المزامنة لجعل الأداء أفضل ويستخدم ثابت لضمان التفرد.
3. وضع ثابت
بعد إنشاء الحالة الداخلية للفئة ، لن يتغير خلال فترة الحياة بأكملها.
لا يتطلب وضع UNCANGERINGINGING
قم بإنشاء فئة غير متغيرة:
منتج الفئة النهائية العامة {// تأكد من عدم وجود سلسلة نهائية خاصة من الفئة الفرعية ؛ // لن يتم الحصول على السمات الخاصة بواسطة اسم السلسلة النهائية الخاصة بكائنات أخرى ؛ // الضمانات النهائية بعدم تعيين السمة مرتين سعر مزدوج ؛ المنتج العام (سلسلة لا ، اسم السلسلة ، السعر المزدوج) {// عند إنشاء كائن ، يجب تحديد البيانات Super () ؛ // لأنه بعد الخلق ، لا يمكن تعديل هذا. no = لا ؛ this.name = name ؛ this.price = السعر ؛ } السلسلة العامة getno () {return no ؛ } السلسلة العامة getName () {return name ؛ } public double getPrice () {return price ؛ }} تشمل حالات الأنماط غير المتغيرة في جافا:
java.lang.string
java.lang.boolean
java.lang.byte
java.lang.character
java.lang.double
java.lang.float
java.lang.integer
java.lang.long
java.lang.short
4. الوضع المستقبلي
الفكرة الأساسية هي المكالمات غير المتزامنة
غير متزامن:
غير متزامن:
يتم إرجاع أول call_return حيث لم يتم الانتهاء من المهمة بعد.
ولكن هذه العائدات تشبه الطلب في التسوق ، ويمكنك الحصول على نتيجة بناءً على هذا الطلب في المستقبل.
لذلك يعني هذا النموذج المستقبلي أنه يمكن الحصول على "المستقبل" ، مما يعني أن الأمر أو العقد هو "الوعد" وسيعطي النتيجة في المستقبل.
التنفيذ البسيط للوضع المستقبلي:
ما يحصل عليه المتصل هو بيانات ، والتي قد تكون Futuredata في البداية ، لأن RealData بطيئة في البناء. في وقت ما في المستقبل ، يمكن الحصول على RealData من خلال Futuredata.
تنفيذ الكود:
بيانات الواجهة العامة {public string getResult () ؛ } الفئة العامة Futuredata تنفذ البيانات {محمية RealData RealData = null ؛ . setRealData المتزامنة العامة المزامنة (RealData RealData) {if (isReady) {return ؛ } this.realdata = alldata ؛ isReady = صحيح ؛ إخطار () ؛ // تم حقن realdata ، وإخطار getResult ()} السلسلة المزامنة العامة getResult () // سوف تنتظر بنية RealData لإكمال {بينما (! isReady) {try {wait () ؛ // انتظر طوال الوقت لمعرفة أن RealData تم حقنها} catch (interruptedException e) {}} return alldata.result ؛ // تنفذها RealData}} تنفذ الفئة العامة RealData Data {النتيجة المحمية للسلسلة النهائية ؛ Public RealData (String Para) {// قد يكون بناء RealData بطيئًا للغاية ويتطلب من المستخدم الانتظار لفترة طويلة. هنا نستخدم Sleep لمحاكاة StringBuffer SB = New StringBuffer () ؛ لـ (int i = 0 ؛ i <10 ؛ i ++) {sb.append (para) ؛ جرب {// استخدم النوم هنا بدلاً من سلسلة تشغيل بطيئة جدًا. sleep (100) ؛ } catch (interruptedException e) {}} النتيجة = sb.toString () ؛ } سلسلة عامة getResult () {return return ؛ }} Client Client {public data request (Final String Querystr) {Final Futuredata Future = New Futuredata () ؛ New Thread () {public void run () {// RealData بطيئة جدًا في البناء ، // حتى RealData في سلسلة رسائل منفصلة realData = new RealData (Querystr) ؛ Future.setRealData (RealData) ؛ } } }.يبدأ()؛ العودة في المستقبل // سيتم إرجاع Futuredata على الفور}} الفراغ الثابت العام (String [] args) {client client = new client () ؛ // سيتم إرجاع هذا على الفور لأن ما تحصل عليه هو Futuredata بدلاً من بيانات RealData = client.request ("الاسم") ؛ system.out.println ("request upplication") ؛ جرب {// هنا يمكنك استخدام النوم بدلاً من معالجة منطقات الأعمال الأخرى // في عملية معالجة منطق الأعمال هذه ، يتم إنشاء RealData ، مع الاستفادة الكاملة من موضوع وقت الانتظار. Sleep (2000) ؛ } catch (interruptedException e) {} // استخدم data system.out.println ("data =" + data.getResult ()) ؛ }هناك أيضًا العديد من دعم الوضع المستقبلي في JDK:
بعد ذلك ، استخدم الفئات والأساليب التي توفرها JDK لتنفيذ الرمز الآن:
استيراد java.util.concurrent.callable ؛ الطبقة العامة realdata تنفذ قابلة للاتصال <string> {private string para ؛ Public RealData (String Para) {this.para = para ؛ } Override Public String Call () يلقي الاستثناء {StringBuffer SB = جديد StringBuffer () ؛ لـ (int i = 0 ؛ i <10 ؛ i ++) {sb.append (para) ؛ حاول {thread.sleep (100) ؛ } catch (interruptedException e) {}} return sb.toString () ؛ }} استيراد java.util.concurrent.executionexception ؛ استيراد java.util.concurrent.executorservice ؛ استيراد java.util.concurrent.executors ؛ استيراد java.util.concurrent.futureTask ؛ فئة عامة futuremain {public static void main ( FutureTaskase FutureTask <String> Future = New FutureTask <String> (New RealData ("A")) ؛ ExecutorService Executor = Executors.NewFixedThreadPool (1) ؛ // تنفيذ futureTask ، أي ما يعادل client.request ("A") في المثال أعلاه إرسال طلب // تمكين مؤشر الترابط هنا لأداء استدعاء realdata () وتنفيذ executor.submit (المستقبل) ؛ system.out.println ("request upplication") ؛ جرب {// لا يزال من الممكن إجراء عمليات بيانات إضافية هنا ، ويمكن استخدام النوم بدلاً من معالجة موضوع منطق الأعمال الآخر. Sleep (2000) ؛ } catch (interruptedException e) {} // مكافئة لـ data.getResult () ، احصل على قيمة الإرجاع لطريقة call () // إذا لم يتم تنفيذ طريقة الاتصال () في هذا الوقت ، فستظل تنتظر system.out.println ("data =" + future.get ()) ؛ }} ما تحتاج إلى ملاحظته هنا هو أن FutureTask هو فئة لها وظيفة مستقبلية ووظيفة يمكن تشغيلها. لذلك يمكن تشغيله مرة أخرى ، وأخيراً الحصول عليه.
بالطبع ، إذا كانت البيانات الحقيقية غير جاهزة عند الاتصال بـ Future.get () ، فستظل تتسبب في وضع حظر حتى تصبح البيانات جاهزة.
بالطبع هناك طرق أسهل:
استيراد java.util.concurrent.executionException ؛ استيراد java.util.concurrent.executorservice ؛ استيراد java.util.concurrent.executors ؛ استيراد java.util.concurrent.future Executors.NewFixedThreadPool (1) ؛ // تنفيذ futureTask ، أي ما يعادل client.request ("a") في المثال أعلاه أرسل طلبًا // افتح مؤشر الترابط هنا لأداء استدعاء realdata () وتنفيذ المستقبل <string> future = executor.submit (new RealData ("a")) ؛ system.out.println ("request upplication") ؛ جرب {// لا يزال من الممكن إجراء عمليات بيانات إضافية هنا ، استخدم النوم بدلاً من Thread. Sleep (2000) ؛ } catch (interruptedException e) {} // مكافئة لـ data.getResult () ، احصل على قيمة الإرجاع لطريقة call () // إذا لم يتم تنفيذ طريقة call () في هذا الوقت ، ستظل System.out.println تنتظر system.out.println ("data =" + future.get ()) ؛ }} نظرًا لأن Callable لها قيمة إرجاع ، يمكنك إرجاع الكائن المستقبلي مباشرة.
5. المنتج والمستهلك
نموذج المنتج المستهلك هو نموذج تصميم كلاسيكي متعدد الخيوط. يوفر حلاً جيدًا للتعاون بين سلاسل الرسائل المتعددة. في نموذج المنتج المستهلك ، عادة ما يكون هناك نوعان من الخيوط ، وهما العديد من مؤشرات الترابط المنتج والعديد من مؤشرات الترابط المستهلك. يعد مؤشر ترابط المنتج مسؤولاً عن تقديم طلبات المستخدم ، بينما يكون مؤشر ترابط المستهلك مسؤولاً عن التعامل مع المهام التي يقدمها المنتج على وجه التحديد. يتواصل المنتج والمستهلك من خلال مخزن مؤقت للذاكرة المشتركة.
لقد كتبت مقالًا في الماضي لتنفيذ طرق مختلفة لاستخدام Java لتنفيذ المنتجين والمستهلكين ، لذلك لن أشرح ذلك هنا.