Programming Basics SQL HTML CSS JavaScript React Python C++ Java JavaFX Swing Problem Solving English English Conversations Computer Fundamentals Linux Learn Typing

تعريف مبدأ المسؤولية الواحدة (SRP)

  • تعريف مبدأ SRP
  • قبل اتباع مبدأ SRP
  • إعادة هيكلة الكود ليتبع مبدأ SRP
  • فوائد تطبيق مبدأ SRP

تعريف مبدأ SRP

مبدأ المسؤولية الواحدة ( SRP ) إختصاراً ينص على أنه يجب أن يكون لكل كلاس أو دالة سبب واحد فقط للتغيير، بمعنى أنه يجب أن يكون مسؤولاً عن مهمة واحدة فقط، مما يجعله أكثر تنظيماً و قابلية للتعديل دون التأثير على وظائف أخرى.

أحرف SRP هي اختصار لعبارة Single Responsibility Principle التي تعني مبدأ المسؤولية الواحدة.

قبل اتباع مبدأ SRP

في المثال التالي يوجد انتهاك لمبدأ SRP في الكلاس UserController حيث أنه يقوم بأكثر مهمة و هي:

  1. التحقق من صحة البيانات.
  2. إنشاء المستخدم.
  3. إرسال رسالة عبر البريد الإلكتروني.

مثال

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 دون التأثير على باقي النظام.
آخر تحديث في 28-03-2025

Mohammed Ammar Ammar

محمد عمار عمار مطور تطبيقات باستخدام Laravel, Vue, React أمتلك خبرة جانبية ب: Nodejs Python, Flask, Pandas

ammar4web.github.io

تعليقات

لا يوجد أي تعليق بعد

أضف تعليق

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