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