نمط الكائن الفارغ

في البرمجة الكائنية التوجه ، يُعرف الكائن الفارغ بأنه كائن لا توجد له قيمة مرجعية أو ذو سلوك محايد ( فارغ ) محدد. وقد نُشر نمط تصميم الكائن الفارغ ، الذي يصف استخدامات هذه الكائنات وسلوكها (أو انعدامه)، لأول مرة تحت اسم "القيمة الفارغة" [ 1 ] ، ثم لاحقًا في سلسلة كتب "لغات أنماط تصميم البرامج " تحت اسم "الكائن الفارغ" [ 2 ] .

تحفيز

في معظم لغات البرمجة كائنية التوجه، مثل جافا أو سي شارب ، قد تكون المراجع فارغة (null ). يجب التحقق من هذه المراجع للتأكد من أنها ليست فارغة قبل استدعاء أي من الدوال ، لأن الدوال لا يمكن استدعاؤها عادةً على مراجع فارغة.

تتخذ لغة Objective -C نهجًا مختلفًا لهذه المشكلة، فلا تفعل شيئًا عند إرسال رسالة إلى الدالة nil؛ إذا كان من المتوقع قيمة مُعادة، فسيتم إرجاع القيمة nil0 (للكائنات)، أو 0 (للقيم العددية)، NOأو 0 BOOL(للقيم)، أو بنية (لأنواع البنى) مع تهيئة جميع أعضائها إلى null0. [ 3 ]NO

وصف

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

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

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

يمكن أيضًا استخدام نمط الكائن الفارغ ليكون بمثابة بديل للاختبار، إذا لم تكن ميزة معينة مثل قاعدة البيانات متاحة للاختبار.

مثال

بافتراض وجود شجرة ثنائية ، ذات بنية العقد التالية:

public class BinaryTree { private BinaryTree left ; private BinaryTree right ;public BinaryTree ( BinaryTree left , BinaryTree right ) { this . left = left ; this . right = right ; }// دوال الوصول، دوال التعيين، الدوال... }

يمكن للمرء تنفيذ إجراء تحديد حجم الشجرة بشكل متكرر:

public class BinaryTree { // ...public int size ( BinaryTree bt ) { return 1 + size ( bt . getLeft ()) + size ( bt . getRight ()); } }

بما أن العقد الفرعية قد لا تكون موجودة، يجب تعديل الإجراء عن طريق إضافة عمليات فحص عدم الوجود أو القيم الفارغة:

public class BinaryTree { // ...public int size ( BinaryTree bt ) { int sum = 1 ; if ( bt.getLeft ( ) != null ) { sum += size ( bt.getLeft ( ) ); } if ( bt.getRight ( ) != null ) { sum + = size ( bt.getRight ( ) ) ; } return sum ; } }

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

public class BinaryTree { // ...public int size ( BinaryTree bt ) { if ( bt == null ) { return 0 ; } else { return 1 + size ( bt . getLeft ()) + size ( bt . getRight ()); } }// في حالة استخدام عامل الشرط الثلاثي: public int size ( BinaryTree bt ) { return bt != null ? 1 + size ( bt . getLeft ()) + size ( bt . getRight ()) : 0 ; } }

هذا يفصل المنطق العادي عن معالجة الحالات الخاصة ويجعل الكود أسهل للفهم.

العلاقة بالأنماط الأخرى

يمكن اعتبارها حالة خاصة من نمط الدولة ونمط الاستراتيجية .

إنها ليست نمطًا من أنماط التصميم ، ولكنها مذكورة في كتاب مارتن فاولر لإعادة البناء [ 4 ] وكتاب جوشوا كيريفسكي لإعادة البناء إلى الأنماط [ 5 ] باسم إعادة بناء إدراج كائن فارغ .

الفصل 17 من كتاب روبرت سيسيل مارتن " تطوير البرمجيات الرشيقة: المبادئ والأنماط والممارسات " [ 6 ] مخصص للنمط.

البدائل

ابتداءً من C# 6.0، أصبح من الممكن استخدام عامل التشغيل "؟" ( المعروف أيضًا باسم عامل التشغيل الشرطي الفارغ )، والذي سيتم تقييمه ببساطة إلى قيمة فارغة إذا كان المعامل الأيسر فارغًا.

namespace Wikipedia.Examples ;// قم بالتجميع كتطبيق وحدة تحكم، يتطلب C# 6.0 أو أعلى باستخدام System ;public class Program { static void Main ( string [] args ) { string str = "test" ; Console . WriteLine ( str ?. Length ); Console . ReadKey (); } } // سيكون الناتج: // 4

أساليب التمديد ودمج القيم الفارغة

في بعض لغات Microsoft .NET ، يمكن استخدام دوال الإضافة لتنفيذ ما يُسمى "دمج القيم الفارغة". وذلك لأن دوال الإضافة يُمكن استدعاؤها على القيم الفارغة كما لو كانت "استدعاء دالة مثيل"، بينما هي في الواقع دوال ثابتة. يُمكن برمجة دوال الإضافة للتحقق من القيم الفارغة، مما يُعفي الكود الذي يستخدمها من القيام بذلك. لاحظ أن المثال أدناه يستخدم عامل دمج القيم الفارغة في لغة C# لضمان استدعاء خالٍ من الأخطاء، بينما كان من الممكن استخدام عبارة if...then...else أبسط. يعمل المثال التالي فقط عندما لا تُبالي بوجود القيم الفارغة، أو عندما تُعامل القيم الفارغة والسلاسل النصية الفارغة بنفس الطريقة. قد لا ينطبق هذا الافتراض في تطبيقات أخرى.

namespace Wikipedia.Examples ;// قم بالتجميع كتطبيق وحدة تحكم، يتطلب C# 3.0 أو أعلى باستخدام System ؛ باستخدام System.Linq ؛static class StringExtensions { public static int SafeGetLength ( this string valueOrNull ) { return ( valueOrNull ?? String . Empty ). Length ; } }public static class Program { // تعريف بعض السلاسل النصية static const string [] MY_STRINGS = new [] { "Mr X." , "Katrien Duck" , null , "Q" };// كتابة الطول الإجمالي لجميع السلاسل النصية في المصفوفة public static void Main ( string [] args ) { IEnumerable < int > query = from text in MY_STRINGS select text . SafeGetLength (); // لا حاجة لإجراء أي فحوصات هنا Console . WriteLine ( query . Sum ()); } } // سيكون الناتج: // 18

بلغات مختلفة

لغة سي++

توضح لغة ذات مراجع ثابتة النوع للكائنات كيف يصبح الكائن الفارغ نمطًا أكثر تعقيدًا:

استيراد std ؛باستخدام std :: unique_ptr ؛class Animal { public : virtual ~ Animal () = default ;virtual void makeSound () const = 0 ; };class Dog : public Animal { public : virtual void makeSound () const override { std :: println ( "نباح!" ); } };class NullAnimal : public Animal { public : virtual void makeSound () const override { // صمت... } };int main () { unique_ptr < Animal > dog = std :: make_unique < Dog > (); dog -> makeSound (); // يُخرج صوت "نباح!"unique_ptr <Animal> unknown = std :: make_unique <NullAnimal> ( ); unknown- > makeSound ( ); // لا يُخرج أي شيء ، لكنه لا يُطلق استثناءً أثناء التشغيل }

الفكرة هنا هي أنه توجد حالات Animalتتطلب مؤشرًا أو مرجعًا لكائن ما، ولكن لا يتوفر كائن مناسب. المرجع الفارغ غير ممكن في لغة C++ المتوافقة مع المعايير. Animal*المؤشر الفارغ ممكن، وقد يكون مفيدًا كعنصر نائب، لكن لا يجوز استخدامه للإرسال المباشر: a->makeSound()يُعد سلوكًا غير مُعرَّف إذا aكان المؤشر فارغًا.

يحل نمط الكائن الفارغ هذه المشكلة من خلال توفير NullAnimalفئة خاصة يمكن إنشاء مثيل لها مرتبطة بمؤشر Animalأو مرجع.

يجب إنشاء فئة فارغة خاصة لكل تسلسل هرمي للفئات التي يجب أن تحتوي على كائن فارغ، لأن a NullAnimalلا فائدة منه عندما يكون المطلوب هو كائن فارغ فيما يتعلق بفئة Widgetأساسية لا علاقة لها بالتسلسل Animalالهرمي.

تجدر الإشارة إلى أن عدم وجود فئة فارغة (null) يُعدّ ميزةً مهمة، على عكس اللغات التي تُعتبر فيها أي قيمة مرجعية (مثل Java وC#). في لغة C++، قد يُحدد تصميم الدالة أو الطريقة صراحةً ما إذا كان مسموحًا بقيمة فارغة أم لا.

// دالة تتطلب كائنًا من نوع Animal، ولن تقبل قيمة فارغة (null). void doSomething ( const Animal & animal ) { // لا يمكن أن تكون قيمة animal فارغة (null) هنا. }// دالة قد تقبل كائنًا من نوع Animal أو قيمة فارغة (null). void doSomething ( const Animal * animal ) { // قد تكون قيمة animal فارغة (null). }

سي شارب

لغة C# هي لغة يمكن فيها تطبيق نمط الكائن الفارغ بشكل صحيح. يوضح هذا المثال كائنات حيوانات تُصدر أصواتًا، مع استخدام كائن NullAnimal بدلاً من الكلمة المفتاحية null في C#. يوفر الكائن الفارغ سلوكًا متسقًا ويمنع حدوث استثناء مرجعي فارغ أثناء التشغيل، والذي قد يحدث في حال استخدام الكلمة المفتاحية null في C#.

namespace Wikipedia.Examples ;// تطبيق نمط الكائن الفارغ: باستخدام النظام ؛// واجهة Animal هي المفتاح لتوافق تطبيقات Animal أدناه. interface IAnimal { void MakeSound (); }// Animal هي الحالة الأساسية. abstract class Animal : IAnimal { // نسخة مشتركة يمكن استخدامها للمقارنات public static readonly IAnimal Null = new NullAnimal (); // حالة Null: يجب استخدام فئة NullAnimal هذه بدلاً من الكلمة المفتاحية null في لغة C#. private class NullAnimal : Animal { public override void MakeSound () { // لا توفر أي سلوك عمدًا. } } public abstract void MakeSound (); }// الكلب حيوان حقيقي. class Dog : Animal { public override void MakeSound () { Console . WriteLine ( "نباح!" ); } }/* ========================= * مثال استخدام بسيط في نقطة دخول رئيسية. */ static class Program { static void Main () { IAnimal dog = new Dog (); dog . MakeSound (); // يُخرج "نباح!"/* بدلاً من استخدام قيمة null في لغة C#، استخدم كائن Animal.Null.  * هذا المثال مبسط ولكنه يوضح فكرة أنه في حال استخدام كائن Animal.Null، فلن يواجه البرنامج *  استثناء System.NullReferenceException في وقت التشغيل، على عكس ما يحدث عند استخدام قيمة null في لغة C#. * /  IAnimal unknown = Animal.Null ; // << يستبدل: IAnimal unknown = null; unknown.MakeSound (); // لا يُخرج أي شيء، ولكنه لا يُطلق استثناءً أثناء التشغيل } }

أحاديث قصيرة

وفقًا لمبدأ سمول توك، كل شيء عبارة عن كائن ، وغياب الكائن نفسه يُنمذج بكائن يُسمى nil. في لغة جنو سمول توك، على سبيل المثال، فئة nilهي UndefinedObject، وهي سليل مباشر لـ Object.

أي عملية لا تُرجع كائنًا مناسبًا لغرضها، يُمكنها إرجاع قيمة nilفارغة، متجنبةً بذلك الحالة الخاصة المتمثلة في إرجاع "لا يوجد كائن" غير المدعومة من قِبل مصممي Smalltalk. تتميز هذه الطريقة بالبساطة (عدم الحاجة إلى حالة خاصة) مقارنةً بالنهج التقليدي "null" أو "لا يوجد كائن" أو "مرجع فارغ". من الرسائل المفيدة بشكل خاص عند استخدامها مع nilهذه الطريقة isNil، الرسائل `null` ifNil:أو `null` ifNotNil:، مما يجعل التعامل مع المراجع المحتملة إلى `null` nilفي برامج Smalltalk عمليًا وآمنًا.

لغة الشفرة الشائعة

في لغة ليسب، يمكن للدوال قبول كائنات خاصة بسلاسة nil، مما يقلل من الحاجة إلى اختبار الحالات الخاصة في كود التطبيق. على سبيل المثال، على الرغم من أن ` nilis` عبارة عن ذرة ولا يحتوي على أي حقول، فإن الدالتين `is` carو` is` cdrتقبلانه nilوتعيدانه مباشرةً، وهو أمر مفيد للغاية ويؤدي إلى كتابة كود أقصر.

بما أن `null` nilهي قائمة فارغة في لغة ليسب، فإن الحالة الموصوفة في المقدمة أعلاه غير موجودة. الكود الذي يُرجع `null` nilيُرجع في الواقع قائمة فارغة (وليس أي شيء يُشبه مرجعًا فارغًا لنوع قائمة)، لذا لا يحتاج المُستدعي إلى اختبار القيمة لمعرفة ما إذا كانت تحتوي على قائمة أم لا.

يدعم البرنامج نمط الكائن الفارغ في معالجة القيم المتعددة. إذا حاول البرنامج استخراج قيمة من تعبير لا يُرجع أي قيمة، فسيتم nilاستبدالها بكائن فارغ. وبالتالي، (list (values))تُرجع الدالة (nil)قائمةً من عنصر واحد تحتوي على قيمة فارغة (nil). (values)لا يُرجع التعبير أي قيمة على الإطلاق، ولكن بما أن استدعاء الدالة listيتطلب اختزال تعبير الوسيط إلى قيمة، فسيتم استبدال الكائن الفارغ تلقائيًا.

إغلاق

في لغة Common Lisp، الكائن nilهو النسخة الوحيدة من الصنف الخاص null. وهذا يعني أنه يمكن تخصيص دالة معينة لهذا nullالصنف، وبالتالي تطبيق نمط تصميم القيمة الفارغة. أي أنه مُدمج أساسًا في نظام الكائنات.

;; فئة الكلب الفارغ( defclass dog () ());; يصدر كائن الكلب صوتًا عن طريق النباح: يتم طباعة woof! على الإخراج القياسي ;; عند استدعاء (make-sound x)، إذا كان x هو مثيل لفئة الكلب.( defmethod make-sound (( obj dog )) ( format t "woof!~%" ));; السماح لـ (make-sound nil) بالعمل عبر التخصيص إلى فئة فارغة. ;; جسم فارغ غير ضار: nil لا يصدر أي صوت. ( defmethod make-sound (( obj null )))

الصنف nullهو صنف فرعي من symbolالصنف ، لأن nilرمز. وبما أن nilيمثل أيضًا القائمة الفارغة، nullفإن هو صنف فرعي من listالصنف أيضًا. وبالتالي، فإن معلمات الطرق المتخصصة في symbolأو listستأخذ nilوسيطًا. بالطبع، nullلا يزال من الممكن تعريف تخصص يكون أكثر تحديدًا لـ nil.

مخطط

على عكس لغة Common Lisp، والعديد من لهجات Lisp، فإن لهجة Scheme لا تحتوي على قيمة nil تعمل بهذه الطريقة؛ لا يمكن تطبيق الدوال carعلى cdrقائمة فارغة؛ لذلك يتعين على كود تطبيق Scheme استخدام دوال الشرط empty?أو pair?لتجنب هذا الموقف، حتى في الحالات التي لا تحتاج فيها لغة Lisp المشابهة جدًا إلى التمييز بين الحالات الفارغة وغير الفارغة بفضل سلوك nil.

روبي

في اللغات ذات الكتابة الديناميكية مثل روبي ، لا يكون توريث اللغة ضروريًا لتوفير السلوك المتوقع.

class Dog def sound "bark" end end class NilAnimal def sound ( * ); end endدالة get_animal ( حيوان = NilAnimal . جديد ) حيوان نهايةget_animal ( Dog.new ) .sound = > " bark " get_animal.sound = > nil

إن محاولات تعديل NilClass مباشرةً بدلاً من توفير تطبيقات صريحة تؤدي إلى آثار جانبية غير متوقعة أكثر من الفوائد.

جافا سكريبت

في اللغات التي تعتمد على الكتابة الديناميكية مثل جافا سكريبت ، لا يكون توريث اللغة ضروريًا لتوفير السلوك المتوقع.

class Dog { sound () { return 'bark' ; } }class NullAnimal { sound () { return null ; } }دالة getAnimal ( النوع ) { إرجاع النوع === 'كلب' ؟ كلب جديد () : حيوان فارغ جديد (); }[ 'dog' , null ] .map (( animal ) => getAnimal ( animal ) .sound ()); // تُرجع ["bark", null]

جافا

package org.wikipedia.examples ;واجهة حيوان { void makeSound (); }class Dog implements Animal { public void makeSound () { System . out . println ( "نباح!" ); } }class NullAnimal implements Animal { public void makeSound () { // الصمت... } }public class Example { public static void main ( String [] args ) { Animal dog = new Dog (); dog . makeSound (); // يُخرج "نباح!"Animal unknown = new NullAnimal (); unknown.makeSound ( ); // لا يُصدر أي صوت ، لكنه لا يُطلق استثناءً أثناء التشغيل } }

يوضح هذا الكود صيغةً معدلةً لمثال C++ المذكور أعلاه، باستخدام لغة Java. كما هو الحال في C++، يمكن إنشاء كائن من فئة فارغة (null) في الحالات التي Animalتتطلب مرجعًا لكائن، ولكن لا يتوفر كائن مناسب. Animalيُمكن إنشاء كائن فارغ ( null Animal myAnimal = null;) وقد يكون مفيدًا كعنصر نائب، ولكن لا يُمكن استخدامه لاستدعاء دالة. في هذا المثال، myAnimal.makeSound();سيُطلق استثناء NullPointerException. لذلك، قد يكون من الضروري إضافة كود إضافي لاختبار الكائنات الفارغة.

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

PHP

واجهة الحيوان { دالة عامة makeSound (); }class Dog implements Animal { public function makeSound () { echo "نباح... \n " ; } }class Cat implements Animal { public function makeSound () { echo "مواء... \n " ; } }class NullAnimal implements Animal { public function makeSound () { // الصمت... } }$animalType = 'elephant' ;دالة إنشاء حيوان من نوع حيوان ( سلسلة $animalType ) : حيوان { بناءً على ( $animalType ) { حالة 'كلب' : إرجاع كائن كلب جديد (); حالة 'قطة' : إرجاع كائن قط جديد (); القيمة الافتراضية : إرجاع كائن حيوان فارغ جديد (); } }makeAnimalFromAnimalType ( $animalType ) -> makeSound (); // ..الحيوان الفارغ لا يصدر أي صوتدالة animalMakeSound ( حيوان $animal ) : void { $animal -> makeSound (); }foreach ([ makeAnimalFromAnimalType ( 'dog' ), makeAnimalFromAnimalType ( 'NullAnimal' ), makeAnimalFromAnimalType ( 'cat' ), ] as $animal ) { // That's also reduce null processing code animalMakeSound ( $animal ); }

فيجوال بيسك دوت نت

يوضح تطبيق نمط الكائن الفارغ التالي كيفية قيام الفئة الملموسة بتوفير كائنها الفارغ المقابل في حقل ثابت Empty. يُستخدم هذا الأسلوب بشكل متكرر في إطار عمل .NET (مثل .NET Framework String.Empty، و.NET Framework EventArgs.Empty، و.NET Framework Guid.Empty، وما إلى ذلك).

Public Class Animal Public Shared ReadOnly Empty As Animal = New AnimalEmpty ()Public Overridable Sub MakeSound () Console.WriteLine ( " Woof! " ) End Sub End Classصديق غير قابل للتوريث، فئة حيوان، فارغ ، يرث حيوانPublic Overrides Sub MakeSound () ' End Sub End Class

نقد

ينبغي استخدام هذا النمط بحذر، لأنه قد يجعل الأخطاء/العيوب تظهر على أنها تنفيذ طبيعي للبرنامج. [ 7 ]

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

انظر أيضاً

مراجع

  1. كوهن، توماس (1996). "القيمة الفارغة". وقائع المؤتمر الدولي الأول حول تكنولوجيا الكائنات الموجهة، ليالي الكائنات البيضاء 1996 (WOON'96)، سانت  بطرسبرغ، روسيا .
  2. وولف، بوبي (1998). "الكائن الفارغ". في مارتن، روبرت؛ ريل، ديرك؛ بوشمان، فرانك (محررون). لغات أنماط تصميم البرامج 3. أديسون-ويسلي.
  3. "العمل مع الكائنات (العمل مع قيمة فارغة)" . مكتبة مطوري iOS . شركة Apple، 13 ديسمبر 2012. تم الاطلاع عليه بتاريخ 19 مايو 2014 .
  4. فاولر، مارتن (1999). إعادة هيكلة الكود: تحسين تصميم الكود الحالي . أديسون-ويسلي. ISBN 0-201-48567-2.
  5. كيريفسكي، جوشوا (2004). إعادة هيكلة البرمجيات باستخدام الأنماط . أديسون-ويسلي. ISBN 0-321-21335-1.
  6. مارتن، روبرت (2002). تطوير البرمجيات الرشيقة: المبادئ والأنماط والممارسات . بيرسون للتعليم. ISBN 0-13-597444-5.
  7. فاولر، مارتن (1999). إعادة الهيكلة، ص 216.