تعريف مبدأ المسؤولية الواحدة (SRP)
- تعريف مبدأ SRP
- قبل اتباع مبدأ SRP
- إعادة هيكلة الكود ليتبع مبدأ SRP
- فوائد تطبيق مبدأ SRP
تعريف مبدأ SRP
مبدأ المسؤولية الواحدة ( SRP ) إختصاراً ينص على أنه يجب أن يكون لكل كلاس أو دالة سبب واحد فقط للتغيير، بمعنى أنه يجب أن يكون مسؤولاً عن مهمة واحدة فقط، مما يجعله أكثر تنظيماً و قابلية للتعديل دون التأثير على وظائف أخرى.
أحرف SRP هي اختصار لعبارة Single Responsibility Principle التي تعني مبدأ المسؤولية الواحدة.
قبل اتباع مبدأ SRP
في المثال التالي يوجد انتهاك لمبدأ SRP في الكلاس UserController
حيث أنه يقوم بأكثر مهمة و هي:
- التحقق من صحة البيانات.
- إنشاء المستخدم.
- إرسال رسالة عبر البريد الإلكتروني.
مثال
class UserController extends Controller { public function store(Request $request) { // هنا سيتم التحقق من صحة البيانات $validatedData = $request->validate([ 'name' => 'required|string|max:255', 'email' => 'required|string|email|max:255|unique:users', 'password' => 'required|string|min:8', ]); // هنا سيتم إنشاء مستخدم جديد $user = User::create([ 'name' => $validatedData['name'], 'email' => $validatedData['email'], 'password' => Hash::make($validatedData['password']), ]); // هنا سيتم إرسال رسالة عبر البريد الإلكتروني Mail::to($user->email)->send(new WelcomeMail($user)); // users في النهاية سيتم إعادة توجيه المستخدم للصفحة return redirect()->route('users.index'); } }
الكود السابق مكتوب بلغة PHP و هو يعتمد على فريموورك Laravel و لكن هذا الأمر غير مهم لأن المبدأ الذي نتكلم عنه يمكن تطبيقه في أي لغة برمجة كانت.
إعادة هيكلة الكود ليتبع مبدأ SRP
سنقوم بإجراء التعديلات الازمة على الكود السابق تباعاً حتى يصبح متبعاً لقواعد SRP.
1- إنشاء Form Request
للتحقق من البيانات
بدلاً من كتابة كود التحقق من البيانات داخل الكلاس UserController
سننقله إلى كلاس إسمه StoreUserRequest
كما يلي.
مثال
class StoreUserRequest extends FormRequest { public function rules() { return [ 'name' => 'required|string|max:255', 'email' => 'required|string|email|max:255|unique:users', 'password' => 'required|string|min:8', ]; } }
إذا تغيرت قواعد التحقق مستقبلاً فإننا سنعدّل فقط على StoreUserRequest
دون لمس UserController
.
2- إنشاء UserService
مسؤول عن إنشاء المستخدم
بدلاً من كتابة كود إنشاء المستخدمين داخل الكلاس UserController
سننقله إلى كلاس إسمه UserService
كما يلي.
مثال
use App\Models\User; use Illuminate\Support\Facades\Hash; class UserService { public function createUser(array $data): User { return User::create([ 'name' => $data['name'], 'email' => $data['email'], 'password' => Hash::make($data['password']), ]); } }
أصبحت مسؤولية إنشاء المستخدم أصبحت في مكان واحد، مما يسهل التعديل عليه لاحقاً.
3- إنشاء EmailService
لإرسال رسائل عبر البريد الإلكتروني
بدلاً من كتابة كود إرسال الرسالة عبر البريد الإلكتروني داخل الكلاس UserController
سننقله إلى كلاس إسمه EmailService
كما يلي.
مثال
use Illuminate\Support\Facades\Mail; use App\Mail\WelcomeMail; use App\Models\User; class EmailService { public function sendWelcomeEmail(User $user): void { Mail::to($user->email)->send(new WelcomeMail($user)); } }
إذا تغيرت طريقة إرسال الرسائل - مثل التحوّل إلى SMS
أو Firebase
- فكل ما علينا فعله هو التعديل على الكلاس EmailService
فقط.
4- تعديل UserController
ليكون أكثر تنظيماً
هكذا سيصبح الكلاس UserController
بعد فصل الكود الذي كان فيه لعدة جزئيات.
مثال
use App\Http\Requests\StoreUserRequest; use App\Services\UserService; use App\Services\EmailService; use Illuminate\Http\RedirectResponse; class UserController extends Controller { protected UserService $userService; protected EmailService $emailService; public function __construct(UserService $userService, EmailService $emailService) { $this->userService = $userService; $this->emailService = $emailService; } public function store(StoreUserRequest $request): RedirectResponse { $user = $this->userService->createUser($request->validated()); $this->emailService->sendWelcomeEmail($user); return redirect()->route('users.index'); } }
UserController
أصبح مسؤولاً فقط عن تنسيق العمليات، بينما التنفيذ الفعلي موزع على الخدمات المختصة.
فوائد تطبيق مبدأ SRP
- توزيع المسؤوليات _ كل كلاس أصبح له مسؤولية واحدة فقط.
- كود أكثر نظافة و تنظيماً _ الكود أصبح سهل التعديل و الصيانة.
- قابلية التوسع _ يمكن استبدال
EmailService
أوUserService
دون التأثير على باقي النظام.