في هذه المقالة ستتعلم المبادئ السوليدية. ستحصل على فهم كل مبدأ منها ومعاينات بالكود الجافا.

تلك المبادئ السوليدية هي مجموعة من خمسة مبادئ تصميم تستخدم في البرمجيات التي تبني التصميم الجمركي. توافق بها سيساعدك على تطوير برمجيات قوية. ستجعل برمجياتك أكثر فعالية وأكثر قابلية للقراءة والتحكم.

سوليد تعني:

  • مبدأ المسؤولية الوحيدة
  • مبدأ الانفتاح/الإغلاق
  • مبدأ التبديل اللسكوفيف
  • مبدأ التنوع في الواجهات
  • مبدأ التبعية في المعادلة

مبدأ المسؤولية الوحيدة

يقول المبدأ الوحيدة أن لكل صنف واحد يجب أن يكون مسؤول عن مسألة واحدة واحدة وسبب تغييره واحد.

public class Employee{
  public String getDesignation(int employeeID){ // }
  public void updateSalary(int employeeID){ // }
  public void sendMail(){ // }
}

في المثال السابق، تمتلك الصنف Employee بعض خصائص الصنف الخاصة بالعمال مثل getDesignation & updateSalary.

بالإضافة إلى ذلك، يوجد أيضًا طريقة تدعى sendMail والتي تتجه بعيدًا عن مسؤولية الصنف Employee.

هذا السلوك ليس خاصًا بهذه الصنف وتخاليفه تخاليف المبدأ الوحيد. لتجنب هذا الخطأ، يمكنك انتقال طريقة sendMail إلى صنف منفصل.

هذه هي الطريقة:

public class Employee{
  public String getDesignation(int employeeID){ // }
  public void updateSalary(int employeeID){ // }
}

public class NotificationService {
    public void sendMail() { // }
}

مبدأ التوسعة والتجنيد

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

public class AreaCalculator(){
  public double area(Shape shape){
    double areaOfShape;
    if(shape instanceof Square){
        // حساب مساحة المربع
    } else if(shape instanceof Circle){
        // حساب مساحة الدوائر
    }
    return areaOfShape;
  }

المشكل بالمثال السابق هو أنه إذا كان هناك مجرد جديد للنوع Shape الذي يتوجب حساب مساحته في المستقبل، يتوجب عليك تعديل الصنف العليا بإضافة قاعدة قراءة else-if أخرى. سوف تقوم بهذا القيام لكل جديد من الأشياء المنفصلة عن الShape.

لتجنب هذا، يمكنك أن تختار واجهة وتجعل كل من أشكال الShape تنفذ هذه الواجهة. ثم، يمكن لكل صنف توفير تطبيقه الخاص لحساب المساحة. هذا سيجعل معرفتك البرمجية سهلة التوسعة في المستقبل.

interface IAreaCalculator(){
  double area();
}

class Square implements IAreaCalculator{
  @Override
  public double area(){
    System.out.println("Calculating area for Square");
    return 0.0;
   }
}

class Circle implements IAreaCalculator{
  @Override
  public double area(){
    System.out.println("Calculating area for Circle");
    return 0.0;
   }
}

مبدأ Liskov الإستبدال

يقول المبدأ Liskov الإستبدال أنه يتوجب أن تستبدل جهة والدة بواحد من أطفالها بدون تأثير على صحة البرنامج.

abstract class Bird{
   abstract void fly();
}

class Eagle extends Bird {
   @Override
   public void fly() { // بعض التطبيقات }
}

class Ostrich extends Bird {
   @Override
   public void fly() { // تطبيق جيد للإعتبار }
}

في المثال العلوي، يتمتع الفئة Eagle والفئة Ostrich كلاهما بتوسيع الفئة Bird وتغيير الطريقة fly(). ومع ذلك، يتم إجبار الفئة Ostrich على توفير تطبيق وهمي لأنها لا تستطيع الطيران، وبالتالي لا تتصرف بنفس الطريقة إذا 替替م الفئة Bird بها.

هذا يخالف مبدأ التبديل الليسكوف. لمعالجة هذه القضية، يمكننا أن نخلق فئة منفصلة للطيور القادرة على الطيران وتمتع الEagle بتوسيعها، بينما يمكن للطيور الأخرى توسيع فئة أخرى لن تشمل أي سلوك لfly.

abstract class FlyingBird{
   abstract void fly();
}

abstract class NonFlyingBird{
   abstract void doSomething();
}

class Eagle extends FlyingBird {
   @Override
   public void fly() { // بعض التنفيذات }
}

class Ostrich extends NonFlyingBird {
   @Override
   public void doSomething() { // بعض التنفيذات }
}

مبدأ التنوع في الواجهات

وفقاً لمبدأ التنوع في الواجهات، يجب أن تبني واجهات صغيرة ومتمركزة ولا تجبر العميل على تنفيذ السلوك الذي لا يحتاجونه.

مثال بسيط سيكون واجهة تقوم بحساب كل من المساحة والكمية لشكل.

interface IShapeAreaCalculator(){
  double calculateArea();
  double calculateVolume();
}

class Square implements IShapeAreaCalculator{
  double calculateArea(){ // حساب المساحة }
  double calculateVolume(){ // تطبيق وهمي }
}

المشكل مع هذا هو أنه إذا تم توفير الشكل المثل المربع، فإنه يجبر التطبيق الcalculateVolume()، الذي لا يحتاج.

في الجهة الأخرى، يمكن للـ كوب تنفيذ الاثنين. لتحجيم هذا الخصوص، يمكننا الفصل عن الواجهة وإنشاء قاعدتان من الواجهات منفصلتان: واحد للحساب من المساحة وآخر للحساب من الكمية. سيسمح هذا للأشكال الفريدة بتقرير ما يجب تنفيذه.

interface IAreaCalculator {
    double calculateArea();
}

interface IVolumeCalculator {
    double calculateVolume();
}

class Square implements IAreaCalculator {
    @Override
    public double calculateArea() { // حساب المساحة }
}

class Cube implements IAreaCalculator, IVolumeCalculator {
    @Override
    public double calculateArea() { // حساب المساحة }

    @Override
    public double calculateVolume() {// حساب الكمية }
}

مبدأ التبعية المعدلة

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

public interface Notification {
    void notify();
}

public class EmailNotification implements Notification {
    public void notify() {
        System.out.println("Sending notification via email");
    }
}

public class Employee {
    private EmailNotification emailNotification; 
    public Employee(EmailNotification emailNotification) {
        this.emailNotification = emailNotification;
    }
    public void notifyUser() {
        emailNotification.notify();
    }
}

في المثال المعطاً، تعتمد الصنف الموظف بشكل مباشر على الصنف تنبيه البريد الإلكتروني، وهو مودulo سطحي. هذا يخالف مبدأ التبعية المعدلة.

public interface Notification{
  public void notify();
}

public class Employee{
  private Notification notification;
  public Employee(Notification notification){
      this.notification = notification;
  }
  public void notifyUser(){
    notification.notify();
  }
 }

 public class EmailNotification implements Notification{
    public void notify(){
        // تنفيذ إشعال التنبيه عن طريق البريد الإلكتروني 
    }
 }

 public static void main(String [] args){
    Notification notification = new EmailNotification();
    Employee employee = new Employee(notification);
    employee.notifyUser();
 }

في مثال الأعلى، قمنا بتأمين الترابط السلي. الموظف لا يعتمد على أي تطبيق عملي بالفعل، بل يعتمد فقط على التجريد (معايير التنبيه).

إذا كان علينا تغيير طريقة الإشعال، يمكننا إنشاء تطبيق جديد وتمريره إلى الـ الموظف.

خلاصة

في الخلاصة، قمنا بتغطية جوهر مبادئ SOLID من خلال أمثلة بسيطة في هذه المقالة.

هذه المبادئ تشكل أساسات لتطوير التطبيقات التي تكون قابلة للتوسعة والتكرار.

لنتواصل على LinkedIn