نمط البناء

نمط البناء هو نمط تصميم يوفر حلاً مرنًا لمختلف مشاكل إنشاء الكائنات في البرمجة كائنية التوجه . يفصل نمط البناء بين بناء الكائن المعقد وتمثيله. وهو أحد أنماط التصميم الكلاسيكية الـ 23 المذكورة في كتاب أنماط التصميم ، ويُصنف ضمن أنماط الإنشاء . [ 1 ]

ملخص

يحل نمط تصميم البناء مشاكل مثل: [ 2 ]

  • كيف يمكن لفئة (نفس عملية البناء) أن تُنشئ تمثيلات مختلفة لكائن معقد؟
  • كيف يمكن تبسيط فئة تتضمن إنشاء كائن معقد؟

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

يصف نمط تصميم البناء كيفية حل مثل هذه المشكلات:

  • قم بتغليف عملية إنشاء وتجميع أجزاء كائن معقد في Builderكائن منفصل.
  • تقوم الفئة بتفويض إنشاء الكائنات إلى Builderكائن بدلاً من إنشاء الكائنات مباشرة.

يمكن للفئة (نفس عملية البناء) أن تفوض إلى Builderكائنات مختلفة لإنشاء تمثيلات مختلفة لكائن معقد.

تعريف

يهدف نمط تصميم البناء إلى فصل عملية بناء كائن معقد عن تمثيله. وبذلك، يمكن لعملية البناء نفسها أن تُنتج تمثيلات مختلفة. [ 1 ]

المزايا

تشمل مزايا نمط البناء ما يلي: [ 3 ]

  • يسمح ذلك بالاختلاف في التمثيل الداخلي للمنتج.
  • يغلف هذا البرنامج التعليمات البرمجية الخاصة بالبناء والتمثيل.
  • يوفر التحكم في خطوات عملية البناء.

العيوب

تشمل عيوب نمط البناء ما يلي:

  • يجب إنشاء نموذج بناء خرساني مميز لكل نوع من أنواع المنتجات. [ 3 ]
  • يجب أن تكون فئات البناء قابلة للتغيير.
  • قد يعيق/يعقد عملية حقن التبعية.
  • في العديد من اللغات الآمنة من القيم الفارغة ، يؤجل نمط البناء أخطاء وقت الترجمة للحقول غير المعينة إلى وقت التشغيل .

بناء

فئات UML ومخطط التسلسل

نموذج لفئة UML ومخطط تسلسل لنمط تصميم البناء. [ 4 ]

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

مخطط الفئات

هيكل البناء
هيكل البناء
  • Builderواجهة مجردة لإنشاء الكائنات (المنتجات).
  • ConcreteBuilder: يوفر التنفيذ لـ Builder. يقوم بإنشاء وتجميع الأجزاء لبناء الكائنات، كمصنع .

أمثلة

لغة سي++

في مثال C++ هذا ، تحتوي الفئة على فئة Computerداخلية Builderتُستخدم لإنشاء كائن Computerمن خلال واجهة برمجة تطبيقات سلسة ، مع جعل المُنشئ خاصًا وجعل build()الطريقة تُرجع مؤشرًا ذكيًا إلى Computerالكائن.

استيراد std ؛باستخدام std :: string ؛ باستخدام std :: unique_ptr ؛class Computer { private : string cpu ; string gpu ; int ram ; // القيمة الافتراضية int storage ; // القيمة الافتراضيةComputer ( string cpu , string gpu , int ram , int storage ) : cpu { std :: move ( cpu )}, gpu { std :: move ( gpu )}, ram { ram }, storage { storage } {} public : ~ Computer () = default ;void showSpecs () { std :: println ( "مواصفات الكمبيوتر:" ); std :: println ( " وحدة المعالجة المركزية: {}" , cpu ); std :: println ( " وحدة معالجة الرسومات: {}" , gpu ); std :: println ( " ذاكرة الوصول العشوائي: {} جيجابايت" , ram ); std :: println ( " مساحة التخزين: {} جيجابايت" , storage ); }class Builder { private : // يتم إعطاء المُنشئ معلمات افتراضية string cpu = "معالج مركزي عام" ; string gpu = "بطاقة رسومات مدمجة" ; int ram = 16 ; int storage = 512 ; public : Builder () = default ;Builder & ofCpu ( string cpu ) noexcept { this -> cpu = std :: move ( cpu ); return * this ; }Builder & ofGpu ( string gpu ) noexcept { this -> gpu = std :: move ( gpu ); return * this ; }Builder & withRam ( int gb ) noexcept { ram = gb ; return * this ; }Builder & withStorage ( int gb ) noexcept { storage = gb ; return * this ; }unique_ptr <Computer> build ( ) { return unique_ptr <Computer> ( new Computer ( cpu , gpu , ram , storage ) ); } } ; } ;int main () { unique_ptr < Computer > myComputer = Computer :: Builder () . ofCpu ( "AMD Ryzen 7" ) . ofGpu ( "NVIDIA RTX 4070" ) . withRam ( 32 ) . withStorage ( 1000 ) . build ();myComputer -> showSpecs (); }

سي شارب

في مثال C#Director هذا، يقوم بتجميع نسخة Bicycleفي المثال أعلاه، ويفوض عملية الإنشاء إلى كائن بناء منفصل تم تقديمه إلى Directorبواسطة Client.

namespace Wikipedia.Examples ;public class Bicycle { // يتم جعل الخصائص إما للقراءة فقط أو للتهيئة فقط لضمان عدم قابليتها للتغيير public string Make { get ; init ; } public string Model { get ; init ; } public int Height { get ; init ; } public string Color { get ; init ; }public Bicycle ( string make , string model , string color , int height ) { Make = make ; Model = model ; Color = color ; Height = height ; } }/// <summary> /// تجريد صحيح للبناء باستخدام طرق Fluent القياسية. /// </summary> public interface IBicycleBuilder { IBicycleBuilder SetColour ( string color ); IBicycleBuilder SetHeight ( int height ); Bicycle Build (); }/// <summary> /// يقوم المُنشئ الملموس بتغليف حالته الخاصة بأمان. /// </summary> public class GTBuilder : IBicycleBuilder { private string _colour = "Black" ; // القيمة الافتراضية private int _height = 26 ; // القيمة الافتراضيةpublic IBicycleBuilder SetColor ( string color ) { _color = color ; return this ; // تُعيد هذه الدالة نفسها لتسلسل استدعاء الدوال }public IBicycleBuilder SetHeight ( int height ) { _height = height ; return this ; }public Bicycle Build () { // يتم التحقق من الصحة هنا قبل إنشاء الكائن إذا لزم الأمر return new Bicycle ( "GT" , "Avalanche" , _color , _height ); } }/// <summary> /// يتحكم المدير في التسلسل باستخدام واجهة البناء السلسة. /// </summary> public class MountainBikeBuildDirector { private readonly IBicycleBuilder _builder ;public MountainBikeBuildDirector ( IBicycleBuilder builder ) { _builder = builder ; }public Bicycle Construct () { // Director formats the steps smooth return _builder . SetColor ( "Red" ) . SetHeight ( 29 ) . Build (); } }

جافا

تستخدم لغة جافا نمط البناء على نطاق واسع. على سبيل المثال، java.lang.StringBuilderالفئة التي تُستخدم لإنشاء java.lang.String. [ 5 ]

StringBuilder sb = new StringBuilder ( ) . append ( "Hello" ) . append ( "", " ) .append ( "world" ) . append ( "!" ) . insert ( 0 , "[INFO]" );String message = sb.toString (); System.out.println ( message ); // يطبع " [ INFO] Hello, world ! "

وبالمثل، يحتوي الصنف على صنف java.util.Localeداخلي Builder، يُستخدم للبناء من خلال دوال الضبط، متجنبًا بذلك استخدام المُنشئ أو of()دوال المصنع. [ 6 ]

استيراد java.util.Locale ؛Locale frenchCanadian = new Locale.Builder ( ) . setLanguage ( " fr" ) // تعيين اللغة إلى الفرنسية . setRegion ( "CA" ) // تعيين المنطقة إلى كندا . setVariant ( "POLY" ) // تعيين متغير مخصص . build (); // إنشاء Locale// يطبع "French (Canada,POLY)" System.out.println ( frenchCanadian.getDisplayName ( ) ) ; // يطبع " fr - CA - x - lvariant-POLY" System.out.println ( frenchCanadian.toLanguageTag ( ) );

تحتوي تدفقات جافا (في ) على واجهةjava.util.stream داخلية تُستخدم لإنشاء الكائنات. [ 7 ]Builder<T>java.util.stream.Stream<E>

بالإضافة إلى ذلك، تحتوي فئات مثل java.net.http.HttpClientو java.net.http.HttpRequestعلى فئات متداخلة Builderبداخلها. [ 8 ] [ 9 ]

الصدأ

في لغة Rust ، يسمح نمط البناء لواجهة برمجة التطبيقات (API) بأن تحتوي على معلمات اختيارية، لأن Rust لا تسمح بالمعلمات الافتراضية أو التحميل الزائد للوظائف .

#[derive(Debug)] pub struct Server { host : String , port : u16 , }impl Server { pub fn builder () -> ServerBuilder { ServerBuilder :: default () } }#[derive(Default)] pub struct ServerBuilder { host : Option < String > , port : Option < u16 > , }impl ServerBuilder { pub fn host ( mut self , host : & str ) -> Self { self . host = Some ( host . to_string ()); self }دالة عامة port ( mut self , port : u16 ) - > Self { self.port = Some ( port ) ; self }pub fn build ( self ) -> Result < Server , &' static str > { let host = self . host . ok_or ( "Host is required" ) ? ; let port = self . port . unwrap_or ( 8080 );موافق ( الخادم { المضيف ، المنفذ }) } }fn main () { let server = Server :: builder () . host ( "127.0.0.1" ) . port ( 3000 ) . build (); println! ( "{:?}" , server ); }

بينما، على عكس لغة C++، لا تسمح لغة Rust بتداخل نوع داخل نوع آخر (مثل Server::Builder)، بدلاً من ذلك Serverقد يكون لديها طريقة builder()لإنشاء ServerBuilder، والتي build()تقوم طريقتها في النهاية بإرجاع Serverمثيل.

انظر أيضاً

ملحوظات

  1. 1 2 جاما وآخرون. 1994 ، ص. 97.
  2. "نمط تصميم البناء - المشكلة والحل والتطبيق" . w3sDesign.com . تم الاطلاع عليه بتاريخ 13 أغسطس 2017 .
  3. 1 2 "فهرس العروض التقديمية /archive/2010/winter/51023-1/presentations" (ملف PDF) . www.classes.cs.uchicago.edu . تاريخ الاسترجاع: 2016-03-03 .
  4. "نمط تصميم البناء - الهيكلة والتعاون" . w3sDesign.com . تم الاطلاع عليه بتاريخ 12 أغسطس 2017 .
  5. شركة أوراكل (7 يوليو 2026). "فئة StringBuilder" . docs.oracle.com . شركة أوراكل.
  6. شركة أوراكل (7 يوليو 2026). "فئة Locale.Builder" . docs.oracle.com . شركة أوراكل.
  7. شركة أوراكل (7 يوليو 2026). "Interface Stream.Builder<T>" . docs.oracle.com . شركة أوراكل.
  8. شركة أوراكل (7 يوليو 2026). "واجهة HttpClient.Builder" . docs.oracle.com . شركة أوراكل.
  9. شركة أوراكل (7 يوليو 2026). "واجهة HttpRequest.Builder" . docs.oracle.com . شركة أوراكل.

مراجع