إعادة بناء التعليمات البرمجية باستخدام الواجهات

مكتمل

في الدرس السابق، تعرفت على تحديات التعليمات البرمجية المقترنة بإحكام وكيفية انتهاكها للمبدأ المفتوح/المغلق. الآن، دعونا نعيد بناء التعليمات البرمجية Library والمثال BorrowableBook لجعل النظام أكثر مرونة وأسهل في الصيانة.

إليك التعليمات البرمجية الأصلية التي توضح المشكلة:

public class BorrowableBook
{
    public string Title { get; set; }
    public bool IsAvailable { get; private set; } = true;

    public BorrowableBook(string title)
    {
        Title = title;
    }

    public void Borrow()
    {
        if (IsAvailable)
        {
            IsAvailable = false;
            Console.WriteLine($"You have borrowed \"{Title}\".");
        }
        else
        {
            Console.WriteLine($"\"{Title}\" is already borrowed.");
        }
    }
}

public class Library
{
    private BorrowableBook _book;

    public Library(BorrowableBook book)
    {
        _book = book;
    }

    public void BorrowBook()
    {
        if (_book.IsAvailable)
        {
            _book.Borrow();
        }
        else
        {
            Console.WriteLine("The book is not available.");
        }
    }
}

يقترن Library هذا التصميم بإحكام بالفئة BorrowableBook ، مما يجعل من الصعب إضافة أنواع جديدة من العناصر القابلة للاقتراض (على سبيل المثال، أقراص DVD) دون تعديل Library الفئة. لإصلاح الاقتران الضيق، نقدم واجهة لفصل سلوك الاقتراض.

تقديم الواجهات

تعين الواجهة عقدا للسلوك دون تفصيل تنفيذه. يؤدي إدخال واجهة إلى تجريد وظيفة الاقتراض وزيادة مرونة النظام.

إليك الواجهة IBorrowable :

public interface IBorrowable
{
    bool IsAvailable { get; }
    void Borrow();
}

تقدم هذه الواجهة عضوين:

  • IsAvailable: خاصية تشير إلى ما إذا كان العنصر متاحا للاقتراض.
  • Borrow: أسلوب لاقتراض العنصر.

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

إعادة بناء التعليمات البرمجية لفئة BorrowableBook

بعد ذلك، نقوم بتحديث BorrowableBook الفئة لتنفيذ الواجهة IBorrowable :

public class BorrowableBook : IBorrowable
{
    public string Title { get; set; }
    public bool IsAvailable { get; private set; } = true;

    public BorrowableBook(string title)
    {
        Title = title;
    }

    public void Borrow()
    {
        if (IsAvailable)
        {
            IsAvailable = false;
            Console.WriteLine($"You have borrowed \"{Title}\".");
        }
        else
        {
            Console.WriteLine($"\"{Title}\" is already borrowed.");
        }
    }
}

الآن، BorrowableBook تلتزم الفئة بالواجهة IBorrowable ، ما يجعلها قابلة للتبديل مع الفئات الأخرى التي تنفذ نفس الواجهة.

إعادة بناء التعليمات البرمجية لفئة المكتبة

نقوم أيضا بتحديث Library الفئة للاعتماد على الواجهة IBorrowable بدلا من فئة الخرسانة BorrowableBook :

public class Library
{
    private IBorrowable _item;

    public Library(IBorrowable item)
    {
        _item = item;
    }

    public void BorrowItem()
    {
        if (_item.IsAvailable)
        {
            _item.Borrow();
        }
        else
        {
            Console.WriteLine("The item is not available.");
        }
    }
}

الآن، يمكن للفئة Library العمل مع أي كائن ينفذ الواجهة IBorrowable ، ما يجعلها أكثر مرونة وأسهل في التوسع.

استخدام إدخال التبعية

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

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

المنشئ في البرمجة يشبه الفني الذي يربط مقابس السماعة أثناء إعداد نظام الاستريو الخاص بك. بالنسبة للفئة Library ، الدالة الإنشائية (public Library(IBorrowable item)) هي المكان الذي يتم فيه توفير التبعية. تسمح الدالة الإنشائية للفئة Library بالعمل مع أي تنفيذ متوافق، مثل BorrowableBook أو BorrowableDVD، دون الحاجة إلى تغيير بنيتها الداخلية. تماما كما يتيح مقبس المتحدث المرونة في اختيار مكبرات صوت مختلفة، تسهل الدالة الإنشائية المرونة في استخدام مختلف العناصر القابلة للاقتراض.

فيما يلي كيفية عملها في التعليمات البرمجية:

public class Library
{
    private IBorrowable _item;

    public Library(IBorrowable item) // Dependency is injected here
    {
        _item = item;
    }

    public void BorrowItem()
    {
        if (_item.IsAvailable)
        {
            _item.Borrow();
        }
        else
        {
            Console.WriteLine("The item is not available.");
        }
    }
}

في هذا المثال:

  • الدالة الإنشائية هي المكان الذي يتم فيه إجراء "الاتصال" (التبعيةIBorrowable)، على غرار كيفية توصيل قابس السماعة ب "المقبس".
  • تعمل الواجهة IBorrowable مثل "مقبس الاستريو"، الذي يحدد نقطة الاتصال القياسية.
  • يشبه و BorrowableBookBorrowableDVD أنواعا مختلفة من سماعات الاستريو مع موصلات فريدة تتصل ب "المقبس".

باستخدام إدخال التبعية، يمكن للفئة Library العمل مع أي تنفيذ ل IBorrowable. يوفر هذا الأسلوب ما يلي:

  • المرونة: يمكنك بسهولة تبديل أو إضافة تطبيقات جديدة دون تعديل Library الفئة.
  • قابلية الاختبار: يمكنك "توصيل" التطبيقات الوهمية لأغراض الاختبار.
  • قابلية الصيانة: Library لا تحتاج الفئة إلى معرفة تفاصيل التنفيذ المحدد، مما يسهل توسيعها وصيانتها.

يضمن هذا التصميم أن Library الفئة لم تعد مقترنة بإحكام بتطبيقات محددة، ما يجعل النظام أكثر نمطية وقابلية للتكيف.

إضافة عناصر جديدة قابلة للاقتراض

مع وجود الواجهة، يمكننا بسهولة إضافة أنواع جديدة من العناصر القابلة للاقتراض دون تعديل Library الفئة. على سبيل المثال، إليك BorrowableDVD فئة:

public class BorrowableDVD : IBorrowable
{
    public string Title { get; set; }
    public bool IsAvailable { get; private set; } = true;

    public BorrowableDVD(string title)
    {
        Title = title;
    }

    public void Borrow()
    {
        if (IsAvailable)
        {
            IsAvailable = false;
            Console.WriteLine($"You have borrowed the DVD \"{Title}\".");
        }
        else
        {
            Console.WriteLine($"The DVD \"{Title}\" is already borrowed.");
        }
    }
}

BorrowableDVD تنفذ الفئة نفس IBorrowable الواجهة، بحيث يمكن استخدامها بسلاسة Library مع الفئة.

اختبار النظام

فيما يلي برنامج لإظهار النظام الذي تمت إعادة بناء التعليمات البرمجية له:

using System;

class Program
{
    static void Main()
    {
        // Create borrowable items
        IBorrowable book = new BorrowableBook("Adventure Works Cycles");
        IBorrowable dvd = new BorrowableDVD("Graphic Design Institute");

        // Create libraries
        Library bookLibrary = new Library(book);
        Library dvdLibrary = new Library(dvd);

        // Borrow items
        bookLibrary.BorrowItem();
        bookLibrary.BorrowItem(); // Try borrowing again

        Console.WriteLine();

        dvdLibrary.BorrowItem();
        dvdLibrary.BorrowItem(); // Try borrowing again
    }
}

يوضح الإخراج مرونة النظام المعاد بناء التعليمات البرمجية:

You have borrowed "Adventure Works Cycles".
"Adventure Works Cycles" is already borrowed.

You have borrowed the DVD "Graphic Design Institute".
The DVD "Graphic Design Institute" is already borrowed.

يوضح هذا المثال المعاد بناء التعليمات البرمجية كيفية تقليل الواجهات للتبعيات وتحسين الوحدات النمطية:

  • فصل المخاوف: تعزل الواجهة IBorrowable سلوك الاقتراض، ما Library يضمن عدم اعتماد الفئة على تطبيقات محددة.
  • مرونة محسنة: يمكنك إضافة أنواع جديدة من العناصر القابلة للاقتراض (على سبيل المثال، أقراص DVD) دون تعديل Library الفئة.
  • الصيانة المبسطة: يسهل فهم النظام واختباره وتوسيعه لأن المسؤوليات مقسمة بوضوح.