مقدمة: لماذا تعتبر مبادئ SOLID مهمة لمطور Swift
\nفي عالم تطوير iOS، يعد إنشاء كود قابل للصيانة والتوسع مهمة رئيسية. تظل مبادئ SOLID، التي صاغها روبرت مارتن، المعيار الذهبي لهندسة البرمجيات. على المستوى المتقدم، يتيح إتقان هذه المبادئ في Swift ليس فقط كتابة كود نظيف، بل أيضًا بناء أنظمة مرنة قادرة على تحمل تغييرات المتطلبات. في هذه المقالة، سنحلل كل مبدأ مع أمثلة بلغة Swift، مع التركيز على المهام الواقعية لمطور iOS/macOS.
\n\n1. مبدأ المسؤولية الفردية (SRP) في Swift
\nالنظرية: يجب أن يكون لكل فئة أو هيكل سبب واحد فقط للتغيير. عمليًا، هذا يعني أن الوحدة مسؤولة عن مهمة واحدة محددة بوضوح.
\n\nالمشكلة: ViewController مثقل بالمهام
\nفي UIKit، غالبًا ما توجد وحدات تحكم تدير واجهة المستخدم وتعالج طلبات الشبكة وتحفظ البيانات في نفس الوقت. هذا ينتهك مبدأ SRP.
\n// ❌ انتهاك SRP\nclass UserViewController: UIViewController {\n @IBOutlet weak var tableView: UITableView!\n private var users: [User] = []\n\n override func viewDidLoad() {\n super.viewDidLoad()\n fetchUsers()\n }\n\n private func fetchUsers() {\n // طلب شبكة\n URLSession.shared.dataTask(with: URL(string: "https://api.example.com/users")!) { data, _, _ in\n // تحليل JSON\n // حفظ في Core Data\n DispatchQueue.main.async {\n self.tableView.reloadData()\n }\n }.resume()\n }\n}\n\nالحل: فصل المسؤوليات
\nنقوم بنقل التعامل مع البيانات والشبكة إلى خدمات منفصلة.
\n// ✅ SRP: خدمة منفصلة للتعامل مع المستخدمين\nprotocol UserServiceProtocol {\n func fetchUsers(completion: @escaping (Result<[User], Error>) -> Void)\n}\n\nclass UserService: UserServiceProtocol {\n func fetchUsers(completion: @escaping (Result<[User], Error>) -> Void) {\n // منطق طلب الشبكة\n }\n}\n\n// ✅ SRP: مدير منفصل لـ Core Data\nclass CoreDataManager {\n func saveUsers(_ users: [User]) {\n // حفظ في Core Data\n }\n}\n\n// ✅ SRP: ViewController يدير واجهة المستخدم فقط\nclass UserViewController: UIViewController {\n private let userService: UserServiceProtocol\n private let coreDataManager: CoreDataManager\n\n init(userService: UserServiceProtocol, coreDataManager: CoreDataManager) {\n self.userService = userService\n self.coreDataManager = coreDataManager\n super.init(nibName: nil, bundle: nil)\n }\n\n override func viewDidLoad() {\n super.viewDidLoad()\n loadUsers()\n }\n\n private func loadUsers() {\n userService.fetchUsers { [weak self] result in\n switch result {\n case .success(let users):\n self?.coreDataManager.saveUsers(users)\n self?.updateUI(with: users)\n case .failure(let error):\n self?.showError(error)\n }\n }\n }\n}\n\n2. مبدأ الانفتاح/الإغلاق (OCP) وبروتوكولات Swift
\nالنظرية: يجب أن تكون الكيانات البرمجية (الفئات، الوحدات) مفتوحة للتمديد ولكن مغلقة للتعديل. في Swift، يتم تحقيق ذلك من خلال البروتوكولات والوراثة.
\n\nمثال: نظام الإشعارات
\n// ❌ انتهاك OCP: عند إضافة نوع جديد من الإشعارات، يجب تغيير switch\nclass NotificationSender {\n func send(_ notification: Notification, type: String) {\n switch type {\n case "email":\n // إرسال بريد إلكتروني\n case "push":\n // إرسال إشعار فوري\n default:\n break\n }\n }\n}\n\n// ✅ OCP: استخدام بروتوكول\nprotocol NotificationChannel {\n func send(_ notification: Notification)\n}\n\nclass EmailChannel: NotificationChannel {\n func send(_ notification: Notification)