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

كما في
الجزء الأول ، يتم تجميع الاختصارات ، إذا كان ذلك منطقيًا. إذا لم يكن هناك أي معنى ، فسيتم سردها أبجديًا.
التزامن والعمليات الذرية:•
CAS•
ABA•
القوات المسلحة الأنغولية•
RCUتخزين البيانات:•
حمض•
CAP•
PACELC•
قاعدةمبادئ تطوير البرمجيات:•
جاف•
قبلة•
YAGNI•
المعاهد الوطنية للصحة•
FTSE•
فهم•
الصلبةأخرى:•
أبي•
بقرة•
FBC ، FBCP•
LRUالتزامن والعمليات الذرية
CAS
قارن و المبادلة. مقارنة مع الصرف. هذا هو تعليمة ذرية مع ثلاث وسائط: المتغير الذري أو عنوان الذاكرة ، القيمة المتوقعة ، القيمة الجديدة. إذا وفقط إذا كانت قيمة المتغير مطابقة للقيمة المتوقعة ، فسيحصل المتغير على قيمة جديدة ويكتمل التعليمة بنجاح. إما أن تقوم
CAS بإرجاع قيمة منطقية (ومن ثم يمكن تسميتها مقارنة وضبط) ، أو إذا فشلت ، فإنها تُرجع القيمة الحالية للوسيطة الأولى.
الكود الزائفbool cas(int* addr, int& expected, int new_value) { if (*addr != expected) { expected = *addr; return false; } *addr = new_value; return true; }
في C ++ ، يتم تمثيل
CAS بعائلات الأساليب
std::atomic<T>::compare_exchange_weak
،
std::atomic<T>::compare_exchange_strong
والوظائف المجانية
std::atomic_compare_exchange_weak
،
std::atomic_compare_exchange_strong
. الفرق بين
* ضعيف و
* قوي هو أن الأول يمكن أن يؤدي إلى نتائج سلبية خاطئة. أي إذا كانت القيمة متوقعة ، فسوف تُرجع
false
ولن تستبدلها بأخرى جديدة. السبب في وجود عمليات
ضعيفة هو أنه في بعض البنايات ،
تكون المكلفة
قوية نسبيا. في معظم الحالات ، تدور تعليمات
CAS في حلقة (ما يسمى حلقة CAS) ، لذا فإن استخدام
* ضعيف بدلاً من
* قوي لن يغير المنطق ، ولكنه يمكن أن يحسن الأداء.
تُستخدم إرشادات
CAS لتنفيذ بدائل التزامن (مثل المزامنة والأشارات) والخوارزميات الخالية من القفل. غالبا ما تؤدي إلى مشكلة
ABA .
اقرأ المزيد:
مرة واحدة (الروسية) ،
اثنان (الإنجليزية)ABA
مشكلة ABA. مشكلة ABA. تنشأ هذه المشكلة في خوارزميات متوازية تستند إلى مقارنات مع التبادلات (انظر
CAS ) ، على سبيل المثال ، في خوارزميات خالية من القفل. خلاصة القول هي أن مؤشر الترابط يقرأ قيمة المتغير الذري ، ويقوم بشيء آخر ويقوم بتحديث هذا المتغير من خلال المقارنة مع التبادل. أي يكون منطق التدفق كما يلي: إذا كان المتغير لا يزال يحتوي على القيمة السابقة ، فلن يتغير شيء ، كل شيء في محله. لكن هذا قد لا يكون كذلك. وصف أكثر رسمية للمشكلة:
- يقرأ مؤشر الترابط 1 قيمة المتغير ، وهو يساوي A
- يتم فرض مؤشر ترابط 1 خارج ، مؤشر الترابط 2 يبدأ
- مؤشر الترابط 2 يغير قيمة المتغير من A إلى B ، ويقوم بمجموعة من التغييرات (يغير بعض القيمة المرتبطة بالمتغير أو يحرر الذاكرة فقط) ، ثم يغير القيمة مرة أخرى - من B إلى A
- مؤشر الترابط 1 يستأنف العملية ، ويقارن القيمة التي تم الحصول عليها مسبقًا مع القيمة الحالية ويستنتج أنه لم يتغير شيء
الحلول الممكنة للمشكلة:
- أبسط والأكثر وضوحا هو استخدام الأقفال. سيؤدي هذا إلى خوارزمية آمنة لمؤشر الترابط المعتادة مع أقسام هامة. لكنها ستتوقف عن أن تكون خالية من الأقفال. ولكن إذا كان الأمر يتعلق بـ CAS و ABA ، فمن المرجح أن هذا ليس خيارًا.
- إضافة تسميات خاصة إلى القيم المقارنة. على سبيل المثال ، عداد لعدد التغييرات. من ناحية ، قد يتجاوز هذا العداد ، ولكن من ناحية أخرى ، تدعم معالجات x86_64 الحديثة عمليات CAS 128 بت. أي عند مقارنة المؤشرات بأحد العدادات ، يمكنك إعطاء ما يصل إلى 64 بت ، واعتبر شخص ما أن هذا يكفي لمدة 10 سنوات من التشغيل المستمر للخوارزمية.
- توفر بعض البنيات (ARM ، على سبيل المثال) إرشادات LL / SC (تحميل مرتبط ، مشروط بالتخزين) لا تسمح لك فقط بالحصول على القيمة الحالية للعنوان في الذاكرة ، ولكن أيضًا لفهم ما إذا كانت هذه القيمة قد تغيرت منذ آخر قراءة.
لاستخدام هياكل البيانات مثل مكدس أو قائمة أو قائمة انتظار خالية من الأقفال بشكل عام ، حيث يكون هناك خطر من البقاء مع مؤشر معلق إلى عقدة بعيدة ، هناك مجموعة كاملة من الحلول لمشكلة
ABA بناءً على إزالة العقد المؤجلة. يتضمن ذلك جامع البيانات المهملة ومؤشرات الخطر وآلية القراءة والكتابة للقراءة (انظر
RCU ).
اقرأ المزيد:
واحد (الروسية) واثنان (الإنجليزية) وثلاثة (الإنجليزية)FAA
إحضار وإضافة. مهم ... الحصول على وإضافة (يبدو أن هذا المفهوم لا يترجم إلى اللغة الروسية). عملية ذرية مع وسيطين: متغير ذري أو عنوان في الذاكرة ، والقيمة التي يجب تغيير هذا المتغير بواسطتها. إذا سمحت البنية ، فإن العملية تُرجع القيمة السابقة للمتغير الذي تم تغييره (يسمح x86 منذ i486). على عكس
CAS ، فإن
FAA ناجحة دائمًا.
الكود الزائف int faa(int* addr, int diff) { int value = *addr; *addr = value + diff; return value; }
في C ++ ، يتم تطبيقه على أنه مجموعة من الأساليب
std::atomic<T>::fetch_add
fetch_xor
و
fetch_xor
و
fetch_xor
و
fetch_xor
و
fetch_xor
والوظائف الحرة المقابلة
std::atomic_fetch_add
، إلخ.
كما يلائم تعليمات ذرية ، يتم استخدام
FAA في تطبيقات بدائل التزامن وخوارزميات خالية من القفل وهياكل البيانات.
اقرأ المزيد:
مرة واحدة (الروسية) ،
اثنان (الإنجليزية)RCU
قراءة نسخة التحديث. قراءة تعديل والكتابة. هذه آلية غير محظورة لمزامنة الوصول إلى بنية البيانات (خالية من القفل بالطبع). يتم استخدامه في الحالات التي تكون فيها سرعة القراءة حرجة. إنه مثال على المفاضلة بين الوقت والذاكرة (المفاضلة بين الفضاء والمكان).
فكرة
RCU هي أن دفق الكاتب لا يغير البيانات الموجودة ، لكنه ينشئ نسخة ، ويقوم بالتغيير اللازم فيها ويتبادل البيانات الحالية والنسخة التي تم تغييرها تلقائيًا. في الوقت نفسه ، تتمتع مؤشرات ترابط القارئ باستمرار بالوصول إلى البيانات - القديمة أو الجديدة ، أيا كان لديه الوقت. في حالة عدم وجود قارئات تركوا العمل مع الإصدار القديم ، يحذف الكاتب البيانات التي لم تعد مطلوبة ، مما يؤدي إلى تحرير الذاكرة.
تعمل RCU المبسطة جدًا مثل هذا:
- العديد من القراء ، كاتب واحد.
- القراءة والتغيير تحدث في وقت واحد.
- يستخدم القراء تزامن خفيف الوزن للغاية. في الواقع ، يتعين على القارئ فقط إخطار الكاتب في لحظة دخوله القسم النقدي وفي لحظة مغادرته. يحدث العمل مع البيانات المتزامنة فقط في القسم الحرج.
- الكاتب ، حالما يستعاض عن البيانات آلياً بنسخة ، يعلن عن بداية فترة السماح (فترة السماح). تنتهي فترة السماح عندما يترك جميع القراء الذين كانوا في أقسام حرجة في بداية هذه الفترة أقسامهم الحرجة. الآن يمكن للكاتب حذف البيانات القديمة بأمان. من المفترض أن تكون جميع الأقسام الحرجة محدودة ، مما يضمن دقة فترة السماح.
تعد RCU رائعة بالنسبة للبيانات التي غالبًا ما تتم قراءتها ونادراً ما يتم تحديثها. يتم استخدام هذه الآلية بنشاط في نواة Linux ، حيث يكون من السهل جدًا تحديد وقت انتهاء فترة السماح.
العيوب:
- ضعيف لمزامنة الوصول إلى البيانات المعدلة بشكل متكرر.
- من الصعب تنفيذها في مساحة المستخدم.
- يعتمد على القدرة على تغيير المؤشرات تلقائيًا إلى عنوان في الذاكرة ، ولكن لا توفر كل البنى هذه الإمكانية.
اقرأ المزيد:
مرة واحدة (الروسية) ،
اثنان (الإنجليزية)تخزين البيانات
ACID
atomicity ، الاتساق ، العزلة ، المتانة. الذرية ، الاتساق ، العزلة ، المتانة. هذه هي مجموعة من متطلبات المعاملة في DBMS. يوفر
ACID عملية DBMS موثوقة ويمكن التنبؤ بها حتى في حالة وجود أخطاء.
- Atomicity يضمن أن الصفقة إما أن تكتمل تماما أو لا تفعل شيئا. الدولة الوسيطة مستحيلة ، ولن تكون عملية معاملة واحدة ناجحة ، والآخر غير ناجح. كل شيء أو لا شيء.
- يضمن الاتساق أن جميع البيانات الموجودة في قاعدة البيانات تلبي جميع القواعد والقيود المحددة قبل بدء المعاملة وبعد اكتمالها. أثناء تنفيذ المعاملة ، قد يتم انتهاك الاتساق.
- عزل يضمن المعاملات المتزامنة لا تؤثر على بعضها البعض. لا توجد معاملة لها حق الوصول إلى بيانات غير متسقة تتم معالجتها بواسطة معاملة أخرى.
- المتانة تعني أن نتيجة المعاملة الناجحة يتم تخزينها في قاعدة البيانات ولا يمكن فقدانها ، بغض النظر عما يحدث لقاعدة البيانات فور اكتمال المعاملة.
جميع نظم إدارة قواعد البيانات العلائقية الرئيسية تدعم
ACID بشكل كامل. في عالم NoSQL ، من المرجح أن يكون هذا الدعم الكامل استثناءً.
اقرأ المزيد:
مرة واحدة
(الإنجليزية) ،
اثنان (الإنجليزية)CAP
نظرية كاب. نظرية كاب. تنص النظرية على أنه لا يمكن أن يحتوي أي نظام موزع على أكثر من خاصيتين من القائمة: تناسق البيانات (
الاتساق ) ، التوفر (
الإتاحة ) ، مقاومة الفصل (
تحمل التقسيم ).
- الاتساق في هذه الحالة يعني الاتساق الثابت (المبسط). أي بمجرد اكتمال عملية تحديث البيانات على عقدة واحدة بنجاح ، فإن جميع العقد الأخرى لديها بالفعل هذه البيانات المحدثة. وفقا لذلك ، جميع العقد في حالة ثابتة. ليس هذا هو الاتساق المطلوب من قبل ACID .
- يعني التوفر أن كل عقدة فاشلة تقوم بإرجاع إجابة صحيحة لكل طلب (سواء للقراءة والكتابة) في فترة زمنية معقولة. ليس هناك ما يضمن تطابق الردود من العقد المختلفة.
- مقاومة الفصل تعني أن النظام سيستمر في العمل بشكل صحيح في حالة فقدان عدد تعسفي من الرسائل بين العقد.
لأن جميع الخصائص الثلاثة غير قابلة للتحقيق ؛ من وجهة نظر نظرية
CAP ، تنقسم جميع الأنظمة الموزعة إلى ثلاث فئات:
CA و
CP و
AP .
من الواضح أن أنظمة
CA لا تملك مقاومة فصل. لأن في الغالبية العظمى من الحالات ، يعني التوزيع توزيعا عبر شبكة حقيقية ، وفي شبكة حقيقية هناك دائما احتمال غير صفري بفقدان حزمة ، ثم أنظمة
CA ليست ذات أهمية تذكر.
الاختيار بين
CP و
AP ، أي بين الاتساق والتوافر. DBMSs العلائقية التقليدية التي تتبع مبادئ
ACID تفضل الاتساق. بينما تختار العديد من حلول NoSQL إمكانية الوصول و
BASE .
في حالة التشغيل العادي للشبكة ، أي عندما لا يكون هناك فصل للشبكة ، فإن نظرية
CAP لا تفرض أي قيود على الاتساق والتوافر. أي التبرع بشيء غير ضروري.
اقرأ المزيد:
واحد (الروسية) واثنان (الإنجليزية) وثلاثة (الإنجليزية)PACELC
نظرية PACELC. نظرية PACELC. هذا امتداد لنظرية
CAP ، التي تنص على أن النظام الموزع في حالة قسم الشبكة (
Partition ) مجبر على الاختيار بين
التوافر (
الاتساق ) ، وفي حالة تشغيل الشبكة العادي (
Else ) ، يجب عليك الاختيار بين الكمون (
الاتساق) ).
وفقًا لذلك ، إذا ميزت نظرية
CAP فئتين من الأنظمة المستقرة مع فصل الشبكة ، فإن
PACELC لديها 4 منها:
PA / EL و
PA / EC و
PC / EL و
PC / EC . يمكن لبعض قواعد بيانات NoSQL تغيير فئتها اعتمادًا على الإعدادات.
اقرأ المزيد:
مرة واحدة (الروسية) ،
اثنان (الإنجليزية)BASE
المتاحة أساسا ، الدولة الناعمة ، الاتساق في نهاية المطاف. التوافر الأساسي ، الحالة الهشة ، الاتساق على المدى الطويل. وفقًا لنظرية
CAP في الأنظمة الموزعة ، يجب التخلي عن شيء ما. عادة ما يتم التخلي عن التماسك الصارم لصالح التماسك على المدى الطويل. مما يعني أنه في حالة عدم وجود تغييرات في البيانات ، سيصل النظام في يوم ما إلى حالة متسقة.
للإشارة إلى مثل هذا الحل الوسط ، بدأ استخدام
قاعدة الاختصار
BASE بإحكام إلى حد ما ،
وانتهت لعبة المصطلحات الكيميائية (
ACID - الحموضة ،
BASE - الأساسيات).
- متوفر بشكل أساسي يعني أن النظام يضمن توافر البيانات ، فإنه يستجيب لكل طلب. ولكن قد تكون الإجابة بيانات قديمة أو غير متسقة (أو تفتقر إليها)
- الحالة المرنة تعني أن حالة النظام يمكن أن تتغير بمرور الوقت حتى في حالة عدم وجود طلبات لتغيير البيانات. لأنه في أي وقت من الأوقات ، يمكن جلب البيانات إلى حالة متسقة.
- التناسق النهائي يعني أنه إذا توقفت البيانات عن التغيير ، فإنها ستنتهي بالطبع في حالة متسقة. أي نفس الطلب إلى عقد مختلفة سيؤدي إلى نفس الإجابات.
اقرأ المزيد:
مرة واحدة
(الإنجليزية) ،
اثنان (الإنجليزية)مبادئ تطوير البرمجيات
DRY
لا تكرر نفسك. لا تكرر. هذا هو مبدأ تطوير البرمجيات ، والفكرة الرئيسية منها هي تقليل كمية المعلومات المكررة في النظام ، والهدف هو تقليل تعقيد النظام وزيادة قابليته للإدارة.
في الأصل (
المبرمج البراغماتي ،
أندرو هانت وديفيد توماس ) تم صياغة هذا المبدأ على النحو التالي: "يجب أن يكون لكل قطعة معرفة تمثيل واحد ثابت وموثوق داخل النظام." في هذه الحالة ، تُفهم المعرفة على أنها تعني أي جزء من مجال أو خوارزمية موضوع: رمز ، مخطط قاعدة بيانات ، بروتوكول تفاعل معين ، وما إلى ذلك. ومن أجل إجراء تغيير واحد على النظام ، يجب تحديث "معرفة" واحدة فقط في مكان واحد.
مثال غبي: يقوم العميل والخادم بنقل البيانات المنظمة إلى بعضهما البعض. لأن هذه تطبيقات مختلفة تعمل على أجهزة مختلفة ، ثم يجب أن يكون لكل منهما تطبيقات خاصة بهذين الهيكلين. إذا تغير شيء ما ، فسيتعين إجراء التغييرات في مكانين. تتمثل إحدى الخطوات الواضحة لتجنب هذا التكرار في تخصيص الكود الشائع في مكتبة منفصلة. تتمثل الخطوة التالية في إنشائها وفقًا لوصف الهياكل (مخازن بروتوكول Google ، على سبيل المثال) ، حتى لا تكتب نفس نوع الكود للوصول إلى حقول الهياكل.
رمز الازدواجية هو مجرد حالة خاصة من انتهاك
DRY . وهذا ليس هو الحال دائما. إذا كانت هناك شطرين من التعليمات البرمجية متشابهان ، ولكن كل منهما يطبق منطق أعمالهما ، فلن
يتم كسر
DRY .
مثل أي مبدأ آخر ،
DRY هو أداة ، وليس عقيدة. كلما كان النظام أكبر ، كان من الأسهل انتهاك هذا المبدأ. أولاً ، المثل الأعلى بعيد المنال. وثانياً ، إذا كان اتباع
DRY بشكل أعمى يؤدي إلى رمز أكثر تعقيدًا وجعل فهمه أكثر صعوبة ، فمن الأفضل التخلي عنه.
اقرأ المزيد:
واحد (الروسية) واثنان (الروسية)KISS
يبقيه بسيط ، غبي. اجعل الأمر أسهل (ليس غبي في هذه الحالة مكالمة). هذا هو مبدأ التصميم الذي تعمل به معظم الأنظمة بشكل أفضل إذا ظلت بسيطة. نشأ هذا المبدأ في صناعة الطائرات ويتم تطبيقه كثيرًا ، بما في ذلك تطوير البرمجيات.
في الحالة الأخيرة ، تعتبر
KISS مفيدة في تصميم وكتابة التعليمات البرمجية مباشرةً. الهندسة المعمارية البسيطة والرمز ليس فقط أسهل للفهم ، بل هي أيضًا سهلة الاستخدام والصيانة والتطوير. لا ينبغي خداع MapReduce إذا كان الزوج المنتج والمستهلك كافيًا. سحر metaprogramming معقد للغاية إذا كنت تستطيع القيام ببعض الوظائف العادية وتحقيق المستوى المطلوب من الأداء.
مع كل هذا ، يجب ألا ينسى المرء أن البساطة ليست هدفًا ، بل مجرد مطلب غير وظيفي. الشيء الرئيسي هو تحقيق هدف التصميم / التنفيذ ، ومن المستحسن القيام بذلك بأبسط طريقة ممكنة.
اقرأ المزيد:
واحد (روسي) واثنان (روسي) وثلاثة (انجليزي)YAGNI
لن تحتاجها. لا تحتاجها. هذا هو مبدأ تطوير البرمجيات ، والذي تتمثل الفكرة الرئيسية في رفض الوظيفة المفرطة ، والهدف من ذلك هو توفير الموارد التي تنفق على التطوير.
يقول
YAGNI أنك لست بحاجة إلى تصميم أو تنفيذ وظائف غير مطلوبة في الوقت الحالي. حتى لو كنت متأكدًا من أنه ستكون هناك حاجة إليها في المستقبل. لا حاجة لإضافة تجريدات غير ضرورية ، ستظهر فوائدها لاحقًا.
المشكلة هي أن الناس لا يتوقعون المستقبل جيدًا. لذلك ، فإن كل شيء على الأرجح "احتياطي" ببساطة لن يكون مفيدًا. وتبين أن الوقت والمال المنفق على هذا التطوير والاختبار والتوثيق يضيعان. بالإضافة إلى ذلك ، أصبح البرنامج أكثر تعقيدًا ؛ يجب إنفاق موارد إضافية على دعمه مرة أخرى. والأسوأ من ذلك ، عندما اتضح أنه كان من الضروري القيام بطريقة مختلفة. سيتم إنفاق المال والوقت أيضًا على التصحيح.
مبدأ
YAGNI أكثر جذرية
إلى حد ما من
DRY و
KISS . إذا قاموا بتقسيم النظام إلى أجزاء يمكن فهمها وجعل القرارات بسيطة ، فإن
YAGNI تقوم ببساطة بقطع الأجزاء والحلول غير الضرورية.
اقرأ المزيد:
واحد (الروسية) واثنان (الإنجليزية) وثلاثة (الإنجليزية)NIH
لم يخترع هنا. لم يخترع هنا. هذا هو متلازمة رفض تطورات الآخرين ، وهو موقف يحد عملياً من اختراع دراجة هوائية. غالبًا ما تصاحب المتلازمة الاعتقاد بأن ابتكار التكنولوجيا داخل الشركة سيكون أسرع وأرخص على حد سواء ، وأن التكنولوجيا نفسها ستلبي بشكل أفضل احتياجات الشركة. ومع ذلك ، في معظم الحالات ، ليس هذا هو الحال ،
والمعاهد الوطنية للصحة هو نمط مضاد.
فيما يلي بعض الحالات التي تبرر
المعاهد الوطنية للصحة :
- جودة حل الجهة الخارجية ليست عالية بما فيه الكفاية ، أو أن السعر ليس منخفضًا بدرجة كافية.
- يحتوي حل الجهة الخارجية على قيود الترخيص.
- باستخدام حل جهة خارجية يخلق الاعتماد على مورديه ، وبالتالي يهدد العمل.
اقرأ المزيد:
واحد (الروسية) واثنان (الإنجليزية) وثلاثة (الإنجليزية)FTSE
النظرية الأساسية لهندسة البرمجيات. النظرية الأساسية لتطوير البرمجيات. في الواقع ، هذه ليست نظرية ؛ ليس لديها دليل. هذا قول مشهور لأندرو كوينيج:
يمكن حل أي مشكلة عن طريق إضافة طبقة أخرى من التجريد.
يضيفون في بعض الأحيان إلى هذه العبارة "... باستثناء مشكلة وجود العديد من طبقات التجريد". بشكل عام ، فإن "النظرية" ليست شيئًا خطيرًا ، لكنها تستحق أن تعرف عنها.
اقرأ المزيد:
مرة واحدة
(الإنجليزية) ،
اثنان (الإنجليزية)GRASP
أنماط برامج تخصيص المسؤولية العامة. قوالب تخصيص المسؤولية العامة. صيغت هذه الأنماط التسعة في
تطبيق UML و Patterns بواسطة
كريج لارمان . يعد كل قالب حلاً نموذجيًا لمشكلة واحدة (ولكن عامة) في تصميم البرامج.
- خبير المعلومات . المشكلة: ما هو المبدأ العام لتوزيع المسؤوليات بين الأشياء؟ القرار: إسناد واجب إلى شخص لديه المعلومات اللازمة للوفاء بهذا الالتزام.
- الخالق (الخالق). المشكلة: من يجب أن يكون مسؤولاً عن إنشاء كائن جديد؟ الحل: يجب على الفئة "ب" إنشاء مثيلات من الفئة "أ" إذا كان واحد أو أكثر من الشروط التالية صحيحاً:
- الفئة B تجمع أو تحتوي على مثيلات من A
- ب يكتب أ
- ب يستخدم بنشاط A
- ب لديه بيانات التهيئة أ - انخفاض اقتران المشكلة: كيف تقلل من تأثير التغيير؟ كيفية زيادة إمكانية إعادة الاستخدام؟ الحل: توزيع المسؤوليات بحيث يكون الاتصال منخفضًا. الاقتران هو مقياس لمدى صلابة العناصر ومدى اعتمادها على بعضها البعض. أي يوصى بتوصيل الكائنات حتى يعرفوا عن بعضهم البعض الحد الأدنى الضروري فقط.
- تستعد عالية ( التماسك عالية ). المشكلة: كيف أدير التعقيد؟ الحل: توزيع المسؤوليات بحيث يتم الحفاظ على مشاركة عالية. المشاركة العالية تعني أن مسؤوليات عنصر واحد تتركز على مجال واحد.
- وحدة تحكم (المراقب المالي). المشكلة: من يجب أن يكون مسؤولاً عن التعامل مع أحداث الإدخال؟ الحل: قم بتعيين فئة لتكون مسؤولة ، والتي تمثل النظام بأكمله أو النظام الفرعي ككل (وحدة تحكم خارجية) ، أو برنامج نصي واحد محدد (وحدة تحكم البرنامج النصي أو الجلسة). في الوقت نفسه ، لا تقوم وحدة التحكم بتطبيق رد فعل على الأحداث ؛ فهي تفوض ذلك إلى المنفذين المعنيين.
- تعدد الأشكال ( تعدد الأشكال ). المشكلة: كيفية التعامل مع السلوكيات المختلفة على أساس النوع؟ : , , , .
- ( Pure Fabrication ). : , ? : , .
- ( Indirection ). : , Low Coupling ? : .
- مقاومة التغييرات ( الاختلافات المحمية ). المشكلة: كيفية تصميم الكائنات والأنظمة الفرعية بحيث لا يكون للتغييرات فيها تأثير غير مرغوب فيه على العناصر الأخرى؟ الحل: يمكنك العثور على نقاط عدم الاستقرار المحتملة وإنشاء واجهة مستقرة من حولهم ، والتواصل فقط من خلال هذه الواجهة.
تتقاطع أنماط GRASP باستمرار مع أنماط Gang Four ومبادئ SOLID . هذا أمر طبيعي ، لأنهم جميعًا يحلون المشكلة الشائعة - لتبسيط إنشاء برامج عالية الجودة.اقرأ المزيد: (. روس) وقت ، اثنان (المهندس) ، ثلاثة (. روس)SOLID
مبادئ الصلبة. هذه هي المبادئ الخمسة للبرمجة والتصميم الموجه للكائنات (يتكون الاختصار من الأحرف الأولى من أسمائهم). اكتسب شهرة بفضل روبرت مارتن في أوائل العقد الأول من القرن العشرين. الهدف الرئيسي من هذه المبادئ هو إنشاء برنامج يسهل فهمه وصيانته وتوسيعه.- مبدأ المسؤولية واحدة ( واحدة مسؤولية المبدأ، وSRP ). يجب أن تتحمل الفئة أو الوحدة التعليمية مسؤولية واحدة فقط. "افعل شيئًا واحدًا فقط ، لكن افعله جيدًا".
- / ( Open Closed Principle, OCP ). (, , ) , . : , .
- ( Liskov Substitution Principle, LSP ). , . أي - .
- ( Interface Segregation Principle, ISP ). , . , . , , . , .
- الاعتماد على عكس مبدأ ( من الاعتماد على عكس المبدأ، وDIP ). يجب ألا تعتمد وحدات المستوى العلوي على وحدات المستوى الأدنى. يجب أن تعتمد جميع الوحدات على التجريد. يجب ألا تعتمد التجريدات على التفاصيل. يجب أن تعتمد التفاصيل على التجريد. على سبيل المثال ، لا يجب أن تحتوي الواجهات أو الفئات الملموسة على فئات ملموسة أخرى أو تقبلها كحجج لأساليبها ، بل واجهات فقط (بمعنى Java و C #).
اقرأ المزيد: (. روس) وقت ، اثنان (المهندس) ، ثلاثة (المهندس)آخر
ABI
واجهة التطبيق الثنائية. واجهة التطبيق الثنائية. هذه مجموعة من الاتفاقيات التي تحدد تفاعل الوحدات الثنائية (الملفات القابلة للتنفيذ ، المكتبات ، نظام التشغيل). يجب إنشاء وحدتين بالتوافق مع أحد ABI - وهذا شرط أساسي لتوافقهما الثنائي ، في هذه الحالة يمكنهم التفاعل دون مشاكل (على سبيل المثال ، الملف القابل للتنفيذ يرتبط بالمكتبة ويتم تنفيذه بواسطة نظام التشغيل).من أمثلة ABI تنسيقات الملفات القابلة للتنفيذ ELF على Linux و PE على Windows. يتوقع كل نظام تشغيل أن البيانات الضرورية (الموارد ، نقطة الإدخال ، إلخ) موجودة في ملف ثنائي وفقًا للتنسيق المقابل. من الواضح أن ELF و PE مختلفان ، لأن برامج Linux لا تعمل مباشرة على Windows والعكس.على مستوى المكتبات والملفات القابلة للتنفيذ ، يمكن لـ ABI تحديد موضع الحقول داخل الفصل ، والفصول الأساسية داخل أحفاد ، وآلية تنفيذ الدالات الافتراضية ، وتنسيق إطار مكدس الاستدعاء ، وقواعد تمرير الوسائط إلى الوظيفة المدعوة ، وما إلى ذلك. إلخ.C ++ معيار ABI ، وهو أمر غير مفاجئ ، لأنه يعتمد على الهندسة المعمارية ونظام التشغيل. على سبيل المثال ، يقوم برنامج التحويل البرمجي لـ C ++ للعديد من أنظمة التشغيل المشابهة لنظام التشغيل Unix (Linux و FreeBSD و MacOS) على x86_64 باتباع System V AMD64 ABI على ARM - ARM C ++ ABI . لم يتم نشر Visual C ++ ABI رسميًا ، ولكن على الأقل تم إعادة تصميمه جزئيًا. إنه مختلف تمامًا عن System V ABI ، وله قواعد مختلفة تمامًا لإخفاء الأسماء (mangling) وتمرير الوسائط إلى الوظيفة المسماة (يستخدم Linux 6 سجلات ، ويستخدم Windows 4 سجلات) ، ومجموعة من الاختلافات الأخرى.حتى إذا بقيت API و ABI كما هي ، وتغيير تفاصيل التطبيق فقط ، فقد يكون التوافق الثنائي معطلًا . على سبيل المثال ، في الإصدار C ++ 11 ، كانت هناك حاجة لسلاسل لتخزين الأحرف بالتسلسل (كما في ناقل). ولهذا السبب ، اضطر مجلس التعاون الخليجي 5 إلى تغيير تنفيذ السلاسل ( تم استخدام COW هناك من قبل ) ، مما أدى إلى عدم توافق ثنائي.اقرأ المزيد: الساعة (. روس) ، عدد (المهندس) ، وجميع الإشارات من الفقرتين السابقتين.COW
نسخ على الكتابة. نسخ على التسجيل. هذه هي آلية إدارة الموارد ، والمعروفة أيضًا باسم المشاركة الضمنية والنسخ البطيئة. الفكرة هي أنه عندما تكون هناك حاجة إلى نسخة ، لا يتم نسخ المورد بالفعل ، ولكن يتم إنشاء رابط إليها. وفقط عندما يكون هناك طلب لإجراء تغييرات - في الأصل أو في "نسخة" - عندها فقط يتم إنشاء نسخة كاملة.ميزة COW واضحة: نسخ أي كائن يحدث على الفور. إذا تم نسخ الكائنات غالبًا ولكن نادرًا ما يتم تغييرها ، فقد تكون مكاسب الأداء كبيرة.أمثلة على استخدام الأبقار :- إدارة الذاكرة العملية الافتراضية في لينكس. عند استدعاء
fork()
الصفحات ، لا يتم نسخ ذاكرة العملية ، ولكن يتم تمييزها فقط على أنها مشتركة. - لقطات في بعض أنظمة الملفات (Btrfs ، ZFS) وقواعد البيانات (MS SQL Server).
- قبل الإصدار C ++ 11 ،
std::string
استخدمت بعض التطبيقات COW . في C ++ 11 ، std::string
تغيرت متطلبات (انظر ABI ). - أنواع كثيرة في كيو تي تستخدم بقرة .
اقرأ المزيد: مرة واحدة (الإنجليزية) ، اثنان (الإنجليزية)FBC ، FBCP
الفئة الأساسية الهشة (مشكلة). مشكلة الطبقة الأساسية الهشة. هذه مشكلة OOP أساسية ، وجوهرها هو أن التغيير الصحيح للفئة الأساسية يمكن أن يؤدي إلى خطأ في أحد الورثة.على سبيل المثال ، إلى العودية لانهائية struct Base { virtual void method1() {
يمكنك حل مشكلة FBC فقط عن طريق التخلي عن الميراث لصالح التكوين ، على سبيل المثال ، أو توسيع الواجهات في مصطلحات Java (في C ++ ، سيكون هذا مورثًا فقط للفئات الأساسية المجردة دون تطبيقات الولاية والطريقة). في حالات أخرى ، يمكنك فقط محاولة تقليل احتمال FBCP بالنصائح التالية:- عدم السماح بالميراث أو إعادة التعريف حيث لا تكون هناك حاجة إليهما (الكلمة الأساسية
final
في C ++ و Java). - لا ينبغي أن يكون للورثة حق الوصول إلى التصميمات الداخلية للفئة الأساسية ، فلا يمكن الاتصال إلا من خلال الواجهة العامة.
- يمكن لطريقة الوريث فقط استدعاء تلك الأساليب الافتراضية التي يتم استدعاؤها بالطريقة المعاد تعريفها للفئة الأساسية ، والطريقة المعاد تعريفها نفسها.
اقرأ المزيد: واحد (الإنجليزية) ، اثنان (الإنجليزية) ، ثلاثة (الإنجليزية)LRU
الأقل استخداما مؤخرا. البثق غير مستخدمة لفترة طويلة. هذه هي إحدى خوارزميات التخزين المؤقت (وهي أيضًا سياسات استباقية). بشكل عام ، يمكن اعتبار ذاكرة التخزين المؤقت تخزينًا سريعًا لأزواج القيمة الرئيسية ، ومن خصائصها الرئيسية نسبة الدخول. كلما كان هذا المستوى أعلى ، كلما كانت القيمة المرغوبة أكثر في ذاكرة التخزين المؤقت السريعة ، وكان يجب البحث عنه في التخزين البطيء. ولكن نظرًا لأن الذاكرة ليست مطاطية أبدًا ، يجب أن يكون حجم ذاكرة التخزين المؤقت محدودًا. تتمثل مهمة خوارزميات التخزين المؤقت في تحديد العنصر الذي يجب التخلص منه من ذاكرة التخزين المؤقت المعبأة ، إذا لزم الأمر ، وذلك لزيادة مستوى الزيارات.LRUيستبدل عنصر ذاكرة التخزين المؤقت ، والذي لم يصله أي شخص إلى أطول وقت ممكن. ربما هذا هو خوارزمية التخزين المؤقت الأكثر شهرة. ربما بسبب مزيج من الكفاءة والبساطة. استهلاك الذاكرة LRU هو O (n) ، ومتوسط وقت الوصول إلى القيمة هو O (1) ، ومتوسط الوقت لإضافة عنصر هو O (1) أيضًا. للتنفيذ ، يتم عادةً استخدام جدول التجزئة وقائمة مرتبطة مضاعفة.على سبيل المثال template <class K, class V> class LRU { private: using Queue = std::list<std::pair<K, V>>; using Iterator = typename Queue::iterator; using Hash = std::unordered_map<K, Iterator>; Queue queue_; Hash hash_; const size_t limit_; public: LRU(size_t limit) : limit_(limit) { } std::optional<V> get(const K& key) { const auto it = hash_.find(key); if (it == hash_.end()) { return {}; } it->second = reorder(it->second); return { it->second->second }; } void add(K&& key, V&& value) { if (hash_.size() >= limit_) { pop(); } queue_.emplace_front(std::move(key), std::move(value)); const auto it = queue_.begin(); hash_[it->first] = it; } private: Iterator reorder(Iterator it) { queue_.emplace_front(std::move(it->first), std::move(it->second)); queue_.erase(it); return queue_.begin(); } void pop() { hash_.erase(queue_.back().first); queue_.pop_back(); } };
يتمثل العيب الواضح في LRU في ارتفاع استهلاك الذاكرة ، لأنه يستخدم بنيتين لكل عنصر n. بالإضافة إلى LRU العديد من خوارزميات الأخرى التخزين المؤقت لمجموعة متنوعة من المناسبات: .. MRU (المستخدمة مؤخرا )، LFU (الأقل كثيرا ما تستخدم)، مقسمة LRU، 2Q ، الخاقرأ المزيد: الساعة (المهندس) ، (. روس) اثنين ، ثلاثة (المهندس)PS
إذا فاتني شيء ما أو كنت مخطئًا في مكان ما - اكتب التعليقات.