مبادئ SOLID في Swift: النظرية والتطبيق من الألف إلى الياء

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

مقدمة في مبادئ SOLID في Swift

\n

كل مطور iOS يواجه عاجلاً أم آجلاً مشكلة "كود السباغيتي": تتضخم الفئات، التغييرات في مكان واحد تكسر التطبيق بأكمله، ويتحول الاختبار إلى كابوس. يكمن حل هذه المشكلات في أساس التصميم الشيئي — مبادئ SOLID. هذه القواعد الخمس، التي صاغها روبرت مارتن، تساعد في إنشاء كود مرن وقابل للصيانة والتوسع بلغة Swift. في هذه المقالة، سنشرح كل مبدأ من النظرية إلى الأمثلة العملية لتطبيقات iOS/macOS.

\n

بغض النظر عما إذا كنت تكتب باستخدام UIKit أو SwiftUI أو AppKit، فإن SOLID هو أساس عالمي. دعنا نتعمق في التفاصيل.

\n\n

1. مبدأ المسؤولية الواحدة (SRP)

\n

النظرية

\n

يجب أن يكون للفئة سبب واحد فقط للتغيير. بمعنى آخر، كل وحدة مسؤولة عن وظيفة واحدة بالضبط. إذا كان ViewController الخاص بك يدير واجهة المستخدم، ويعالج طلبات الشبكة، ويحلل JSON، فهو ينتهك مبدأ SRP.

\n

التطبيق في Swift

\n

لننظر إلى مثال نموذجي — تحميل وعرض بيانات المستخدم.

\n
// ❌ سيء: انتهاك مبدأ SRP\nclass UserViewController: UIViewController {\n    func loadUser() {\n        // طلب شبكة\n        let url = URL(string: "https://api.example.com/user")!\n        URLSession.shared.dataTask(with: url) { data, _, _ in\n            let user = try? JSONDecoder().decode(User.self, from: data!)\n            DispatchQueue.main.async {\n                self.updateUI(with: user)\n            }\n        }.resume()\n    }\n    \n    func updateUI(with user: User?) {\n        // تحديث واجهة المستخدم\n    }\n}
\n
// ✅ جيد: فصل المسؤوليات\nclass UserService {\n    func fetchUser(completion: @escaping (User?) -> Void) {\n        let url = URL(string: "https://api.example.com/user")!\n        URLSession.shared.dataTask(with: url) { data, _, _ in\n            let user = try? JSONDecoder().decode(User.self, from: data!)\n            completion(user)\n        }.resume()\n    }\n}\n\nclass UserViewController: UIViewController {\n    let userService = UserService()\n    \n    func loadUser() {\n        userService.fetchUser { [weak self] user in\n            DispatchQueue.main.async {\n                self?.updateUI(with: user)\n            }\n        }\n    }\n    \n    private func updateUI(with user: User?) {\n        // تحديث واجهة المستخدم\n    }\n}
\n

الخلاصة: الآن UserService مسؤول فقط عن الشبكة، و UserViewController مسؤول عن واجهة المستخدم. التغييرات في منطق الشبكة لا تؤثر على المتحكم.

\n\n

2. مبدأ الفتح/الإغلاق (OCP)

\n

النظرية

\n

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

\n

التطبيق في Swift

\n

تخيل أننا نكتب وحدة لحساب الخصومات في متجر إلكتروني.

\n
// ❌ سيء: عند إضافة خصم جديد، يجب تغيير الفئة\nclass DiscountCalculator {\n    func calculate(price: Double, type: String) -> Double {\n        if type == "seasonal" {\n            return price * 0.9\n        } else if type == "loyalty" {\n            return price * 0.85\n        }\n        return price\n    }\n}
\n
// ✅ جيد: استخدام بروتوكول للتمديد\nprotocol DiscountStrategy {\n    func applyDiscount(to price: Double) -> Double\n}\n\nstruct SeasonalDiscount: DiscountStrategy {\n    func applyDiscount(to price: Double) -> Double {\n        price * 0.9\n    }\n}\n\nstruct LoyaltyDiscount: DiscountStrategy {\n    func applyDiscount(to price: Double) -> Double {\n        price * 0.85\n    }\n}\n\nclass DiscountCalculator {\n    func calculate(price: Double, strategy: DiscountStrategy) -> Double {\n        strategy.                

المدونات

توصيات الكتب