JavaRush /Blog Java /Random-VI /Một cách dễ dàng để thêm phần phụ thuộc

Một cách dễ dàng để thêm phần phụ thuộc

Xuất bản trong nhóm
Tiêm phụ thuộc (DI) không phải là một khái niệm dễ hiểu và việc áp dụng nó vào các ứng dụng mới hoặc hiện có thậm chí còn khó hiểu hơn. Jess Smith chỉ cho bạn cách thực hiện chèn phần phụ thuộc mà không cần hộp chứa nội dung trong ngôn ngữ lập trình C# và Java. Cách tiêm phụ thuộc đơn giản - 1Trong bài viết này, tôi sẽ chỉ cho bạn cách triển khai nội xạ phụ thuộc (DI) trong các ứng dụng .NET và Java. Khái niệm chèn phụ thuộc lần đầu tiên được các nhà phát triển chú ý vào năm 2000, khi Robert Martin viết bài báo "Các nguyên tắc và mẫu thiết kế" (sau này được biết đến với từ viết tắt SOLID ). Chữ D trong SOLID đề cập đến Sự phụ thuộc của đảo ngược (DOI), sau này được gọi là nội xạ phụ thuộc. Định nghĩa ban đầu và phổ biến nhất: đảo ngược phụ thuộc là đảo ngược cách lớp cơ sở quản lý các phụ thuộc. Bài viết gốc của Martin đã sử dụng đoạn mã sau để minh họa sự phụ thuộc của một lớp Copyvào lớp cấp thấp hơn WritePrinter:
void Copy()
	{
	 int c;
	 while ((c = ReadKeyboard()) != EOF)
		WritePrinter(c);
	}
Vấn đề rõ ràng đầu tiên là nếu bạn thay đổi danh sách tham số hoặc loại của một phương thức WritePrinter, bạn cần triển khai cập nhật ở bất kỳ nơi nào có sự phụ thuộc vào phương thức đó. Quá trình này làm tăng chi phí bảo trì và là nguồn tiềm ẩn các lỗi mới.
Bạn muốn đọc về Java? Hãy tham gia nhóm Nhà phát triển Java !
Một vấn đề khác: lớp Copy không còn là ứng cử viên tiềm năng để sử dụng lại. Ví dụ: nếu bạn cần xuất các ký tự được nhập từ bàn phím sang tệp thay vì ra máy in thì sao? Để thực hiện việc này, bạn có thể sửa đổi lớp Copynhư sau (cú pháp ngôn ngữ C++):
void Copy(outputDevice dev)
	{
	int c;
	while ((c = ReadKeyboard()) != EOF)
		if (dev == printer)
			WritePrinter(c);
		else
			WriteDisk(c);
	}
Bất chấp sự ra đời của một phần phụ thuộc mới WriteDisk, tình hình không được cải thiện (mà còn trở nên tồi tệ hơn) vì một nguyên tắc khác đã bị vi phạm: “các thực thể phần mềm, tức là các lớp, mô-đun, hàm, v.v., phải mở để mở rộng, nhưng đóng đối với sửa đổi.” Martin giải thích rằng các câu lệnh if/else có điều kiện mới này làm giảm tính ổn định và tính linh hoạt của mã. Giải pháp là đảo ngược các phần phụ thuộc sao cho phương thức ghi và đọc phụ thuộc vào tệp Copy. Thay vì "bật" các phần phụ thuộc, chúng được chuyển qua hàm tạo. Mã được sửa đổi trông như thế này:
class Reader
	{
		public:
		virtual int Read() = 0;
	};
	class Writer
	{
		public:
		virtual void Write(char) = 0;
	};
	void Copy(Reader& r, Writer& w)
	{
		int c;
		while((c=r.Read()) != EOF)
		w.Write(c);
	}
Giờ đây, lớp này Copycó thể được sử dụng lại dễ dàng bằng cách triển khai các phương thức lớp ReaderWriter. Lớp này Copykhông có bất kỳ thông tin nào về cấu trúc bên trong của các kiểu ReaderWriter, cho phép sử dụng lại chúng với các cách triển khai khác nhau. Nhưng nếu tất cả những điều này có vẻ giống như một điều gì đó khó hiểu đối với bạn, thì có lẽ các ví dụ sau trong Java và C# sẽ làm rõ tình hình.

Ví dụ trong Java và C#

Để minh họa sự dễ dàng của việc chèn phần phụ thuộc mà không cần vùng chứa phần phụ thuộc, hãy bắt đầu bằng một ví dụ đơn giản có thể được tùy chỉnh để sử dụng DIchỉ trong vài bước. Giả sử chúng ta có một lớp HtmlUserPresentationmà khi các phương thức của nó được gọi sẽ tạo ra giao diện người dùng HTML. Đây là một ví dụ đơn giản:
HtmlUserPresentation htmlUserPresentation = new HtmlUserPresentation();
String table = htmlUserPresentation.createTable(rowTableVals, "Login Error Status");
Bất kỳ dự án nào sử dụng mã lớp này sẽ có sự phụ thuộc vào lớp đó HtmlUserPresentation, dẫn đến các vấn đề về khả năng sử dụng và bảo trì được mô tả ở trên. Một cải tiến ngay lập tức được đề xuất: tạo một giao diện có chữ ký của tất cả các phương thức hiện có trong lớp HtmlUserPresentation. Đây là một ví dụ về giao diện này:
public interface IHtmlUserPresentation {
	String createTable(ArrayList rowVals, String caption);
	String createTableRow(String tableCol);
	// Оставшиеся сигнатуры
}
Sau khi tạo giao diện, chúng ta sửa đổi lớp HtmlUserPresentationđể sử dụng nó. Quay lại việc khởi tạo type HtmlUserPresentation, bây giờ chúng ta có thể sử dụng loại giao diện thay vì loại cơ sở:
IHtmlUserPresentation htmlUserPresentation = new HtmlUserPresentation();
String table = htmlUserPresentation.createTable(rowTableVals, "Login Error Status");
Việc tạo một giao diện cho phép chúng ta dễ dàng sử dụng các triển khai khác của IHtmlUserPresentation. Ví dụ: nếu muốn kiểm tra loại này, chúng ta có thể dễ dàng thay thế loại cơ sở HtmlUserPresentationbằng loại khác gọi là HtmlUserPresentationTest. Những thay đổi được thực hiện cho đến nay giúp mã dễ kiểm tra, bảo trì và mở rộng quy mô hơn nhưng không làm gì để sử dụng lại vì tất cả HtmlUserPresentationcác lớp sử dụng loại này vẫn biết về sự tồn tại của nó. Để loại bỏ sự phụ thuộc trực tiếp này, bạn có thể chuyển một loại giao diện IHtmlUserPresentationcho hàm tạo (hoặc danh sách các tham số phương thức) của lớp hoặc phương thức sẽ sử dụng nó:
public UploadFile(IHtmlUserPresentation htmlUserPresentation)
Hàm tạo hiện UploadFilecó quyền truy cập vào tất cả chức năng của loại IHtmlUserPresentation, nhưng không biết gì về cấu trúc bên trong của lớp thực hiện giao diện này. Trong ngữ cảnh này, việc chèn kiểu xảy ra khi một thể hiện của lớp được tạo UploadFile. Một loại giao diện IHtmlUserPresentationcó thể được sử dụng lại bằng cách chuyển các triển khai khác nhau cho các lớp hoặc phương thức khác nhau yêu cầu chức năng khác nhau.

Kết luận và kiến ​​nghị củng cố tài liệu

Bạn đã tìm hiểu về việc chèn phần phụ thuộc và các lớp được cho là phụ thuộc trực tiếp vào nhau khi một trong số chúng khởi tạo một lớp khác để có quyền truy cập vào chức năng của loại mục tiêu. Để tách sự phụ thuộc trực tiếp giữa hai loại, bạn nên tạo một giao diện. Một giao diện cung cấp cho một loại khả năng bao gồm các cách triển khai khác nhau, tùy thuộc vào ngữ cảnh của chức năng được yêu cầu. Bằng cách chuyển một loại giao diện cho một hàm tạo hoặc phương thức của lớp, lớp/phương thức cần chức năng đó sẽ không biết bất kỳ chi tiết nào về loại triển khai giao diện. Do đó, một loại giao diện có thể được sử dụng lại trên các lớp khác nhau yêu cầu hành vi tương tự nhưng không giống hệt nhau.
  • Để thử nghiệm tính năng chèn phụ thuộc, hãy xem mã của bạn từ một hoặc nhiều ứng dụng và thử chuyển đổi loại cơ sở được sử dụng nhiều thành giao diện.

  • Thay đổi các lớp trực tiếp khởi tạo loại cơ sở này để sử dụng loại giao diện mới này và chuyển nó qua hàm tạo hoặc danh sách tham số của phương thức lớp sẽ sử dụng nó.

  • Tạo một triển khai thử nghiệm để kiểm tra loại giao diện này. Khi mã của bạn được cấu trúc lại, DInó sẽ trở nên dễ triển khai hơn và bạn sẽ nhận thấy ứng dụng của mình trở nên linh hoạt hơn nhiều về mặt tái sử dụng và khả năng bảo trì.
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION