การปรับโครงสร้างโดยใช้อินเทอร์เฟซ

เสร็จสมบูรณ์เมื่อ

ในบทเรียนก่อนหน้า คุณได้เรียนรู้เกี่ยวกับความท้าทายของโค้ดคู่ที่หนาแน่นและวิธีการที่ละเมิดหลักการเปิด/ปิด ในตอนนี้ เราปรับโครงสร้างของ 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 ชั้นเรียนอย่างแน่นหนา ทําให้ยากที่จะเพิ่มรายการประเภทใหม่ที่ยืมได้ (ตัวอย่างเช่น ดีวีดี) โดยไม่ต้องปรับเปลี่ยน 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 คลาส

การทดสอบระบบ

นี่คือโปรแกรมที่จะแสดงให้เห็นถึงระบบ refactored:

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
    }
}

เอาต์พุตแสดงให้เห็นถึงความยืดหยุ่นของระบบ refactored:

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 คลาสไม่ขึ้นอยู่กับการใช้งานที่เฉพาะเจาะจง
  • ความยืดหยุ่นที่ดีขึ้น: คุณสามารถเพิ่มประเภทใหม่ของรายการที่สามารถยืมได้ (ตัวอย่างเช่น ดีวีดี) โดยไม่ต้องปรับเปลี่ยน Library คลาส
  • การบํารุงรักษาแบบประยุกต์: ระบบเข้าใจง่ายทดสอบและขยายเวลาเนื่องจากความรับผิดชอบนั้นแบ่งออกอย่างชัดเจน