أنماط التصميم من خلال البرامج التعليمية - قوة OOP (الجزء الثاني)
رحلة نمط التصميم - قوة OOP 2
أنماط التصميم من خلال البرامج التعليمية - قوة OOP (الجزء الثاني)
نمط Singleton: نمط تصميم مفرد وشبه مفرد خالص في Swift نمط Singleton: أنماط التصميم المفردة وشبه المفردة النقية في Swift
المتطلبات الأساسية - تتطلب سلسلة المدونات هذه مستوى متوسطًا من الخبرة في البرمجة الموجهة للكائنات. يجب أن تكون لديك معرفة أساسية بالفئة والكائن والمنشئ والميراث والقيمة ونوع المرجع. سوف يكتسب الوسيط المعرفة وسيقوم الخبراء بصقل معرفتهم من خلال قراءة هذه السلسلة من البداية إلى النهاية. المتطلبات الأساسية - تتطلب سلسلة المدونات هذه خبرة متوسطة في البرمجة الموجهة للكائنات. يجب أن يكون لديك فهم أساسي للفئات والكائنات والمنشئات والميراث والقيمة وأنواع المراجع. سيكتسب المستخدمون المتوسطون المعرفة، بينما سيعمل الخبراء على تحسين معرفتهم من خلال قراءة هذه السلسلة من الغلاف إلى الغلاف.
فئة سينجلتون
فئة سينجلتون
في البرمجة الموجهة للكائنات، الفئة المفردة هي فئة يمكن أن تحتوي على كائن واحد فقط خلال دورة الحياة الكاملة للتطبيق أو المشروع. في البرمجة الشيئية، الفئة المفردة هي فئة يمكن أن تحتوي على كائن واحد فقط خلال دورة الحياة الكاملة للتطبيق أو المشروع.
يعد نمط تصميم Singleton جزءًا من كود دورة حياة تطبيقات iOS. على سبيل المثال، في مشروع iOS، تعد فئة UIApplication أفضل مثال على فئة فردية، والتي يتم إنشاؤها بواسطة نظام iOS عند تشغيل التطبيق وتمريرها إلى AppDelegate كمعلمة في طريقة application:didFinishLaunchingWithOptions:. يعد نمط التصميم المفرد جزءًا من كود دورة حياة تطبيق iOS. على سبيل المثال، في مشروع iOS، تعد فئة UIApplication أفضل مثال على فئة فردية، والتي يتم إنشاؤها بواسطة نظام iOS عند تشغيل التطبيق وتمريرها إلى AppDelegate كمعلمة في الأسلوب application:didFinishLaunchingWithOptions:.
هناك نوعان من أنماط التصميم المفردة.
هناك نوعان من نمط التصميم المفرد.
-
نمط التصميم المفرد النقي نمط تصميم مفرد نقي
-
نمط التصميم شبه المفرد نمط تصميم شبه مفرد
نمط التصميم المفرد النقي:
نمط التصميم النقي المفرد:
في هذا النمط، لا يُسمح للمبرمج الذي يستخدم وظيفة فئة مفردة خالصة بإنشاء مثيل للفئة. يمكن للمبرمج فقط استدعاء الأساليب والوصول إلى الخصائص المتاحة للفئة المفردة باستخدام المثيل المحدد مسبقًا لتلك الفئة. في هذا النمط، لا يُسمح للمبرمجين الذين يستخدمون وظيفة فئة مفردة خالصة بإنشاء مثيلات لتلك الفئة. يمكن للمبرمجين استدعاء الأساليب والوصول إلى الخصائص المتاحة فقط باستخدام مثيل محدد مسبقًا لفئة مفردة.
يتم إنشاء كائن فئة مفردة خالصة تلقائيًا أثناء تشغيل التطبيق باستخدام معلمات محددة مسبقًا ذكرها المطور الذي أنشأ تلك الفئة. أثناء بدء تشغيل التطبيق، يتم تلقائيًا إنشاء كائنات من فئات مفردة خالصة باستخدام معلمات محددة مسبقًا ذكرها المطور الذي أنشأ الفئة.
يجب وضع علامة على فئات Pure-singleton على أنها نهائية لتجنب ارتباك الميراث. في Swift، يمكنك استخدام البنية أيضًا لتحقيق نفس المفهوم. يجب وضع علامة نهائية على الفئات المفردة النقية لتجنب ارتباك الميراث. في Swift، يمكنك أيضًا استخدام البنيات لتنفيذ نفس المفهوم.
لا يمكن للمبرمج أن يرث فئة المفردة النقية. عندما تحاول وراثة أي فئة في Swift، يجب عليك الاتصال بمنشئ الفئة المتفوقة. لا يمكن استدعاء مُنشئ الطبقة المفردة النقية في فئة المفردة النقية لأن جميع مُنشئي فئة المفردة النقية يتم تمييزهم دائمًا على أنهم خاصون. لا يمكن للمبرمجين أن يرثوا من فئات فردية خالصة. عندما تحاول أن ترث من أي فئة في Swift، عليك الاتصال بمنشئ الفئة الفائقة. لا يمكن استدعاء مُنشئ الفئة الفائقة في فئة المفردة النقية لأنه تم وضع علامة على جميع مُنشئي فئة المفرد النقي على أنها خاصة.
دعونا نفهم نمط التصميم هذا بطريقة بسيطة مع المثال أدناه. دعونا نفهم نمط التصميم هذا بطريقة بسيطة من خلال المثال التالي.
//PureSingletonDesignPatterExample1.swift :
// Hitendra Solanki
// Pure-singleton design pattern Playground example
final class LogManager {
//shared and only one available object
static let logger: LogManager = LogManager(databaseURLEndpoint: "https://www.hitendrasolanki.com/logger/live")
private var databaseURLEndpoint: String
//marked as private, no one is allowed to access this initialiser outside of the class
private init(databaseURLEndpoint: String) {
self.databaseURLEndpoint = databaseURLEndpoint
}
func log(_ value: String...){
//complex code to connect to the databaseURLEndpoint and send the value to server directly
}
}
//This is function in playground which executes our test code
func main(){
LogManager.logger.log("test log from medium blog") //this will log on "/live" endpoint
}
//call main to execute our test code
main()
في المثال أعلاه، PureSingletonDesignPatterExample1.swift قمنا بوضع علامة على جميع أساليب init باعتبارها خاصة بفئة LogManger بحيث لا يمكن لأي شخص إنشاء مثيل لتلك الفئة. إذا حاولنا إنشاء فئة فرعية من LogManger، فسوف يعطيك المترجم خطأ. في المثال أعلاه، PureSingletonDesignPatterExample1.swift قمنا بتمييز كافة أساليب init كطرق خاصة لفئة LogManger، لذلك لا يمكن لأحد إنشاء مثيل لهذه الفئة. إذا حاولنا إنشاء فئة فرعية من LogManger، فسوف يعطيك المترجم خطأ.
UIApplication، AppDelegate هي أمثلة على فئة المفردة النقية. هل سبق لك أن حاولت إنشاء كائن من فئة UIApplication يدويًا؟ حاول القيام بذلك وتشغيل التطبيق. [ماذا حدث؟ تعطل التطبيق، أليس كذلك؟ -لقد اختبرت هذا العطل على Swift 5، XCode 10.2] يعد كل من UIApplication وAppDelegate أمثلة على فئات فردية خالصة. هل سبق لك أن حاولت إنشاء كائن من فئة UIApplication يدويًا؟ حاول القيام بذلك وتشغيل التطبيق. تعطل التطبيق، أليس كذلك؟ - لقد اختبرت هذا التعطل في Swift 5، XCode 10.2]
حدود نمط التصميم المفرد النقي،
حدود النمط المفرد النقي،
لا يمكننا اختبار فئة المفردة النقية باستخدام بيانات الاختبار. في المثال أعلاه PureSingletonDesignPatterExample1.swift، لنفترض أنك تريد اختبار فئة LogManager عن طريق توجيهها إلى عنوان URL لوضع الاختبار بدلاً من عنوان URL لوضع الإنتاج، لا يمكننا القيام بذلك عندما نكتب حالات اختبار في هدف XCTest. لا يمكننا اختبار فئات فردية خالصة باستخدام بيانات الاختبار. في المثال أعلاه، PureSingletonDesignPatterExample1.swift، بافتراض أنك تريد اختبار فئة LogManager، قم بتوجيهها إلى عنوان URL لوضع الاختبار بدلاً من عنوان URL لوضع الإنتاج، لا يمكننا القيام بذلك عندما نكتب حالات اختبار في هدف XCTest.يمكننا التغلب على هذا القيد عن طريق تحويل فئة المفردة النقية إلى فئة شبه مفردة أو باستخدام نمط حقن التبعية. سأكتب مقالة مخصصة عن نمط حقن التبعية. في الوقت الحالي، دعونا نواصل نمط التصميم شبه المفرد. يمكننا التغلب على هذا القيد عن طريق تحويل فئة المفردة النقية إلى فئة شبه مفردة أو باستخدام نمط حقن التبعية. سأكتب مقالًا خصيصًا عن أنماط حقن التبعية. الآن، دعونا نواصل استخدام نمط التصميم شبه المفرد.
نمط التصميم شبه المفرد:
نمط التصميم شبه المفرد:
-
في نمط التصميم شبه المفرد، يُسمح للمبرمج الذي يستخدم الفئة بإنشاء كائن من الفئة المفردة إذا لزم الأمر. كما يُسمح أيضًا باستدعاء الأساليب واستخدام خصائص الفئة المفردة. في نمط التصميم شبه المفرد، يمكن للمبرمج الذي يستخدم الفئة إنشاء كائنات من فئة المفردة إذا لزم الأمر. وكذلك الخصائص التي تسمح بطرق الاتصال واستخدام الفئات المفردة.
-
يمكن للمبرمج أيضًا أن يرث فئة شبه مفردة إذا لم يتم وضع علامة على الفئة المفردة على أنها نهائية من قبل مطور فئة المفرد. في نمط التصميم شبه المفرد، ليس من الضروري تحديد الفصل باعتباره نهائيًا. يمكن للمبرمجين أيضًا أن يرثوا من الفئات شبه المفردة إذا لم يضع مطور الفئة المفردة علامة على الفئة المفردة على أنها نهائية. في النمط شبه المفرد، ليس من الضروري وضع علامة على الفصل على أنه نهائي.
//SemiSingletonDesignPatterExample1.swift
// Hitendra Solanki
// Semi-singleton design pattern Playground example
//In semi-singleton design pattern, marking the class as final is optional
final class LogManager {
//shared object
static let logger: LogManager = LogManager(databaseURLEndpoint: "https://www.hitendrasolanki.com/logger/live")
private var databaseURLEndpoint: String
//not marked as private, anyone is allowed to access this initialiser outside of the class
init(databaseURLEndpoint: String) {
self.databaseURLEndpoint = databaseURLEndpoint
}
func log(_ value: String...){
//complex code to connect to the databaseURLEndpoint and send the value to server directly
}
}
//This is function executes our main code
func main(){
LogManager.logger.log("main log from medium blog on live server endpoint") //this will log on "/live" endpoint
}
// This is function executes our TEST MODE code
// Here in playground, Hitendra Solanki created this method for the demostratino purpose only
// Usually we write this kind of test codes, inside the test targe of the XCode-project
func testThatLogManger(){
//we are allowed to create an instace of class LogManager,
//because it follows the Semi-Singleton design patterns
let logManagerTestObject = LogManager(databaseURLEndpoint: "https://www.hitendrasolanki.com/logger/test")
logManagerTestObject.log("test log from medium blog on test server endpoint") //this will log on "/test" endpoint
}
main() //call main
testThatLogManger() //call test execution
- في المثال أعلاه، SemiSingletonDesignPatterExample1.swift، لم نضع علامة على أسلوب init على أنه خاص، لذلك يمكننا إنشاء مثيلات متعددة للفئة شبه المفردة لإزالة التبعية من الخاصية databaseURLEndpoint. يمكننا الآن إنشاء كائن من فئة LogManger باستخدام أي قيمة databaseURLEndpoint، والآن تتبع فئتنا LogManger النمط شبه المفرد. في المثال أعلاه، SemiSingletonDesignPatterExample1.swift، لم نضع علامة على أسلوب init على أنه خاص، حتى نتمكن من إنشاء مثيلات متعددة للفئة شبه المفردة لإزالة التبعية من الخاصية databaseURLEndpoint. يمكننا الآن إنشاء كائنات من فئة LogManger باستخدام أي قيمة لقاعدة البياناتURLEEndpoint والآن تتبع فئتنا LogManger نمطًا شبه مفرد.
يعد UserDefault وFileManager وNotificationCenter أمثلة على الفئات شبه المفردة. يمكننا استخدام كائنات مشتركة محددة مسبقًا مثل UserDefault وFileManager وNotificationCenter وهي UserDefault.standard وFileManager.default وNotificationCenter.default. يعد كل من UserDefault وFileManager وNotificationCenter أمثلة على الفئات شبه المفردة. يمكننا استخدام كائنات مشتركة محددة مسبقًا مثل UserDefault وFileManager وNotificationCenter، وهي UserDefault.standard وFileManager.default وNotificationCenter.default.
الكائن المحدد مسبقًا من الفئات النقية أو شبه المفردة يعيش دائمًا في الذاكرة ولا يتم تدميره أبدًا حتى تقوم بإغلاق التطبيق. كائن محدد من قبل المبرمج من فئة شبه مفردة يتم تدميره بعد اكتمال نطاق الكائن. الكائنات المحددة مسبقًا من الفئات النقية أو شبه المفردة موجودة دائمًا في الذاكرة ولا يتم إتلافها حتى يتم إغلاق التطبيق. يتم تدمير كائن محدد من قبل المبرمج من فئة شبه مفردة بعد اكتمال نطاق الكائن.
سؤال: ما هي الطريقة الأفضل، “نمط التصميم المفرد النقي” أو “نمط التصميم شبه المفرد”، متى يجب أن أستخدم الطريقة الأولى ومتى يجب استخدام الطريقة الأخرى؟ سؤال: أيهما أفضل، “نمط التصميم المفرد النقي” أم “نمط التصميم شبه المفرد”؟ تحت أي ظروف ينبغي استخدامها؟
هذا يعتمد كليًا على مسؤوليات صفك. إذا قمت بإنشاء فئة مفردة في مشروعك وتحتاج إلى تغيير بعض الخصائص في مرحلة ما أو إذا كنت تريد إضافة المزيد من المسؤوليات إلى الفئة عن طريق إضافة طرق جديدة في المستقبل وإذا كنت تحتاج إلى حالات الاختبار الخاصة بها أيضًا مع بيانات وهمية للطرق المضافة حديثًا، فيجب عليك استخدام نمط التصميم شبه المفرد. كل هذا يتوقف على وظيفة فصلك. إذا قمت بإنشاء مشروع فئة مفردة وتحتاج إلى تغيير بعض الخصائص في مرحلة ما، أو في المستقبل تريد إضافة أساليب جديدة، وتحتاج إلى استخدام بيانات وهمية لاختبار الأساليب المضافة حديثًا، فيجب عليك اعتماد نمط التصميم شبه المفرد.
إذا قمت بإنشاء الفصل الخاص بك، فقد انتهيت من اختبار الوحدة وترغب في نشره عبر إطار عمل أو مكتبة، يمكنك استخدام أنماط التصميم المفردة النقية. لأنك أنشأت الفصل وسيستخدمه مطور آخر، لذا فإن اختبار الوحدة لفئتك الفردية هو مسؤوليتك قبل الإصدار، وليس مسؤولية المطور الذي يستخدمه. إذا قمت بإنشاء الفصل الخاص بك، وقمت باختباره بواسطة الوحدة وترغب في توزيعه من خلال إطار عمل أو مكتبة، فيمكنك استخدام نمط التصميم Pure Singleton. نظرًا لأنك أنشأت هذه الفئة، سيستخدمها بعض المطورين الآخرين، لذا فإن اختبار الوحدة للفئة الفردية قبل إصدارها هو مسؤوليتك، وليس مسؤولية المطورين الذين يستخدمونها.
What to read next
Want more posts about Translation?
Posts in the same category are usually the best next step for reading more on this topic.
View same categoryWant to keep following #Translation?
Tags are useful for related tools, specific problems, and similar troubleshooting notes.
View same tagWant to explore another direction?
If you are not sure what to read next, return to the homepage and start from categories, topics, or latest updates.
Back home