Câu trả lời:
Khớp nối chặt chẽ là khi một nhóm các lớp phụ thuộc nhiều vào nhau.
Kịch bản này phát sinh khi một lớp đảm nhận quá nhiều trách nhiệm hoặc khi một mối quan tâm được trải rộng trên nhiều lớp thay vì có lớp riêng.
Khớp nối lỏng lẻo đạt được bằng một thiết kế thúc đẩy trách nhiệm đơn lẻ và tách biệt các mối quan tâm.
Một lớp kết hợp lỏng lẻo có thể được tiêu thụ và kiểm tra độc lập với các lớp (cụ thể) khác.
Giao diện là một công cụ mạnh mẽ để sử dụng để tách rời. Các lớp có thể giao tiếp thông qua các giao diện chứ không phải các lớp cụ thể khác và bất kỳ lớp nào cũng có thể ở phía bên kia của giao tiếp đó chỉ bằng cách thực hiện giao diện.
Ví dụ về khớp nối chặt chẽ:
class CustomerRepository
{
private readonly Database database;
public CustomerRepository(Database database)
{
this.database = database;
}
public void Add(string CustomerName)
{
database.AddRow("Customer", CustomerName);
}
}
class Database
{
public void AddRow(string Table, string Value)
{
}
}
Ví dụ về khớp nối lỏng lẻo:
class CustomerRepository
{
private readonly IDatabase database;
public CustomerRepository(IDatabase database)
{
this.database = database;
}
public void Add(string CustomerName)
{
database.AddRow("Customer", CustomerName);
}
}
interface IDatabase
{
void AddRow(string Table, string Value);
}
class Database implements IDatabase
{
public void AddRow(string Table, string Value)
{
}
}
Một ví dụ khác ở đây .
Mũ được "ghép lỏng lẻo" với cơ thể. Điều này có nghĩa là bạn có thể dễ dàng cởi mũ mà không thực hiện bất kỳ thay đổi nào đối với người / cơ thể. Khi bạn có thể làm điều đó thì bạn có "khớp nối lỏng lẻo". Xem dưới đây để xây dựng.
Hãy nghĩ về làn da của bạn. Nó bị mắc kẹt vào cơ thể bạn. Nó phù hợp như một chiếc găng tay. Nhưng nếu bạn muốn thay đổi màu da của bạn từ nói trắng sang xanh thì sao? Bạn có thể tưởng tượng sẽ đau đớn thế nào khi lột da của bạn, nhuộm nó, và sau đó dán nó trở lại vv? Thay đổi làn da của bạn là khó khăn vì nó được gắn chặt với cơ thể của bạn. Bạn không thể thay đổi dễ dàng. Bạn sẽ phải thiết kế lại một cách cơ bản một con người để biến điều này thành có thể.
Thiên Chúa không phải là một lập trình viên hướng đối tượng tốt.
Bây giờ nghĩ về việc mặc quần áo vào buổi sáng. Bạn không thích màu xanh? Không có vấn đề: bạn có thể đặt một chiếc áo đỏ thay thế. Bạn có thể làm điều này một cách dễ dàng và dễ dàng vì chiếc áo không thực sự kết nối với cơ thể của bạn giống như làn da của bạn. Chiếc áo không biết hoặc quan tâm đến cơ thể nó đang diễn ra . Nói cách khác, bạn có thể thay đổi quần áo mà không thực sự thay đổi cơ thể.
Đó là khái niệm cơ bản trong một tóm tắt.
Điều này quan trọng vì phần mềm luôn thay đổi. Nói chung, bạn muốn có thể dễ dàng sửa đổi mã của mình mà không cần thay đổi mã. Tôi biết rằng âm thanh như một oxymoron, nhưng xin vui lòng chịu đựng với tôi.
Ví dụ về CSV / JSON / DB: Nếu ai đó muốn đầu ra của họ trong tệp CSV chứ không phải JSON, v.v. hoặc nếu bạn muốn chuyển từ MySQL sang PostGreQuery, bạn có thể thực hiện các thay đổi đó cực kỳ dễ dàng trong mã của mình mà không cần phải viết lại toàn bộ lớp, v.v. Nói cách khác, bạn không muốn kết hợp chặt chẽ ứng dụng của mình với việc triển khai cơ sở dữ liệu cụ thể (ví dụ Mysql) hoặc với một đầu ra cụ thể (ví dụ: tệp CSV). Bởi vì, như là không thể tránh khỏi trong phần mềm, những thay đổi sẽ đến. Khi chúng đến, sẽ dễ dàng hơn nhiều nếu các phần mã của bạn được ghép lỏng lẻo.
Linh kiện ô tô Ví dụ: Nếu ai đó muốn xe của họ trong màu đen , bạn không cần phải thiết kế lại toàn bộ xe để làm điều đó. Một chiếc xe hơi và phụ tùng của nó sẽ là một ví dụ hoàn hảo về kiến trúc ghép lỏng lẻo. Nếu bạn muốn thay thế động cơ của mình bằng một động cơ tốt hơn, bạn có thể chỉ cần tháo động cơ của mình mà không cần quá nhiều nỗ lực và trao đổi nó để có một động cơ tốt hơn. Nếu xe của bạn chỉ hoạt động với Động cơ Rolls Royce 1234 và không có động cơ nào khác - thì xe của bạn sẽ được gắn chặt với động cơ đó (Rolls Royce 1234). Sẽ tốt hơn nếu bạn thay đổi thiết kế của chiếc xe của mình để nó sẽ hoạt động với bất kỳđộng cơ, do đó, nó được kết hợp lỏng lẻo hơn với các thành phần của nó. Thậm chí sẽ tốt hơn nếu xe của bạn có thể làm việc mà không cần động cơ! Một số lượng khớp nối sẽ xảy ra, nhưng bạn nên làm việc để giảm thiểu nó nhiều nhất có thể. Tại sao? Bởi vì khi các yêu cầu thay đổi, chúng tôi vẫn có thể cung cấp phần mềm chất lượng tốt, rất nhanh chóng và chúng tôi được hỗ trợ trong mục tiêu đó bằng cách ghép lỏng lẻo.
Trong ngắn hạn, khớp nối lỏng lẻo làm cho mã dễ dàng thay đổi. Các câu trả lời ở trên cung cấp một số mã đáng đọc vào thời điểm này.
Re: @TimoHuovinen bình luận - khái niệm khớp nối lỏng lẻo đi đôi với các khái niệm đa hình. Nếu bạn nắm được sự tương tự cơ bản của áo sơ mi / phụ tùng xe hơi, thì bạn sẽ sẵn sàng để tạo cảm giác đa hình. Cách tốt nhất, tại thời điểm này là đọc các mẫu mã được cung cấp bởi các đồng nghiệp có thể ước tính của tôi trong các câu trả lời khác về chủ đề này. Nếu tôi nói nữa, bạn có thể bị quá tải với quá nhiều thông tin.
Trong thiết kế hướng đối tượng, số lượng khớp nối đề cập đến mức độ thiết kế của một lớp phụ thuộc vào thiết kế của lớp khác. Nói cách khác, mức độ thường xuyên thay đổi trong lớp A thay đổi liên quan đến lực lượng trong lớp B? Khớp nối chặt chẽ có nghĩa là hai lớp thường thay đổi cùng nhau, khớp nối lỏng lẻo có nghĩa là chúng chủ yếu độc lập. Nói chung, nên sử dụng khớp nối lỏng vì dễ kiểm tra và bảo trì hơn.
Bạn có thể thấy bài viết này của Martin Fowler (PDF) hữu ích.
Nói chung, Khớp nối chặt chẽ rất tệ trong hầu hết thời gian, bởi vì nó làm giảm tính linh hoạt và khả năng sử dụng lại mã, nó làm cho các thay đổi trở nên khó khăn hơn nhiều, nó cản trở khả năng kiểm tra, v.v.
Đối tượng liên kết chặt chẽ là một đối tượng cần biết khá nhiều về nhau và thường phụ thuộc nhiều vào các giao diện khác. Thay đổi một đối tượng trong một ứng dụng được liên kết chặt chẽ thường yêu cầu thay đổi một số đối tượng khác, Trong ứng dụng nhỏ, chúng ta có thể dễ dàng xác định các thay đổi và ít có cơ hội bỏ lỡ bất cứ điều gì. Nhưng trong các ứng dụng lớn, các phụ thuộc lẫn nhau này không phải lúc nào cũng được mọi lập trình viên biết đến hoặc có cơ hội để bỏ lỡ các thay đổi. Nhưng mỗi bộ đối tượng liên kết lỏng lẻo không phụ thuộc vào người khác.
Nói tóm lại, chúng ta có thể nói, khớp nối lỏng lẻo là mục tiêu thiết kế nhằm tìm cách giảm sự phụ thuộc lẫn nhau giữa các thành phần của hệ thống với mục tiêu giảm rủi ro thay đổi trong một thành phần sẽ yêu cầu thay đổi trong bất kỳ thành phần nào khác. Khớp nối lỏng lẻo là một khái niệm chung chung hơn nhiều nhằm tăng tính linh hoạt của một hệ thống, làm cho nó dễ bảo trì hơn và làm cho toàn bộ khung 'ổn định hơn'.
Khớp nối đề cập đến mức độ kiến thức trực tiếp mà một yếu tố có của yếu tố khác. chúng ta có thể nói một ví dụ: A và B, chỉ B thay đổi hành vi của nó chỉ khi A thay đổi hành vi của nó. Một hệ thống kết hợp lỏng lẻo có thể dễ dàng được chia thành các yếu tố có thể xác định.
Khi hai đối tượng được ghép lỏng lẻo, chúng có thể tương tác nhưng có rất ít kiến thức về nhau.
Các thiết kế kết hợp lỏng lẻo cho phép chúng tôi xây dựng các hệ thống OO linh hoạt có thể xử lý sự thay đổi.
Mẫu thiết kế quan sát là một ví dụ tốt để làm cho các lớp được ghép lỏng lẻo, bạn có thể xem qua nó trong Wikipedia .
Một trích xuất từ bài viết trên blog của tôi về khớp nối:
Khớp nối chặt chẽ là gì : -
Theo định nghĩa ở trên, một đối tượng liên kết chặt chẽ là một đối tượng cần biết về các đối tượng khác và thường phụ thuộc nhiều vào giao diện của nhau.
Khi chúng ta thay đổi một đối tượng trong một ứng dụng kết hợp chặt chẽ thường thì nó yêu cầu thay đổi đối với một số đối tượng khác. Không có vấn đề gì trong một ứng dụng nhỏ, chúng ta có thể dễ dàng xác định sự thay đổi. Nhưng trong trường hợp một ứng dụng lớn, những sự phụ thuộc lẫn nhau này không phải lúc nào cũng được mọi người tiêu dùng hoặc các nhà phát triển khác biết đến hoặc có nhiều cơ hội thay đổi trong tương lai.
Hãy lấy mã demo của giỏ mua hàng để hiểu về khớp nối chặt chẽ:
namespace DNSLooseCoupling
{
public class ShoppingCart
{
public float Price;
public int Quantity;
public float GetRowItemTotal()
{
return Price * Quantity;
}
}
public class ShoppingCartContents
{
public ShoppingCart[] items;
public float GetCartItemsTotal()
{
float cartTotal = 0;
foreach (ShoppingCart item in items)
{
cartTotal += item.GetRowItemTotal();
}
return cartTotal;
}
}
public class Order
{
private ShoppingCartContents cart;
private float salesTax;
public Order(ShoppingCartContents cart, float salesTax)
{
this.cart = cart;
this.salesTax = salesTax;
}
public float OrderTotal()
{
return cart.GetCartItemsTotal() * (2.0f + salesTax);
}
}
}
Các vấn đề với ví dụ trên
Khớp nối chặt chẽ tạo ra một số khó khăn.
Ở đây, OrderTotal()
phương pháp là cung cấp cho chúng tôi số tiền đầy đủ cho các mặt hàng hiện tại của giỏ hàng. Nếu chúng tôi muốn thêm các tính năng giảm giá trong hệ thống giỏ hàng này. Rất khó để thực hiện mã ở trên vì chúng ta phải thay đổi ở mỗi lớp vì nó được liên kết rất chặt chẽ.
Khớp nối lỏng lẻo có nghĩa là mức độ phụ thuộc giữa hai thành phần là rất thấp.
Ví dụ: SIM GSM
Khớp nối chặt chẽ có nghĩa là mức độ phụ thuộc giữa hai thành phần là rất cao.
Ví dụ: CDMA di động
Theo cách hiểu của tôi, kiến trúc được liên kết chặt chẽ không cung cấp nhiều sự linh hoạt để thay đổi khi so sánh với kiến trúc ghép lỏng lẻo.
Nhưng trong trường hợp các kiến trúc được ghép lỏng lẻo, các định dạng thông báo hoặc nền tảng vận hành hoặc cải tiến logic nghiệp vụ không ảnh hưởng đến đầu kia. Nếu hệ thống bị gỡ xuống để tân trang, dĩ nhiên đầu bên kia sẽ không thể truy cập dịch vụ trong một thời gian nhưng ngoài ra, đầu cuối không thay đổi có thể tiếp tục trao đổi tin nhắn như trước khi tân trang.
Khớp nối chặt chẽ có nghĩa là một lớp phụ thuộc vào lớp khác.
Loose Coupling có nghĩa là một lớp phụ thuộc vào giao diện chứ không phải lớp.
Trong khớp nối chặt chẽ , có sự phụ thuộc mã hóa cứng được khai báo trong các phương thức.
Trong khớp nối lỏng lẻo , chúng ta phải vượt qua sự phụ thuộc bên ngoài vào thời gian chạy thay vì mã hóa cứng. (Hệ thống cặp đôi lỏng lẻo sử dụng giao diện để giảm sự phụ thuộc với lớp.)
Ví dụ: chúng tôi có một hệ thống có thể gửi đầu ra theo hai hoặc nhiều cách như đầu ra JSON, đầu ra CSV, v.v.
public interface OutputGenerator {
public void generateOutput();
}
public class CSVOutputGenerator implements OutputGenerator {
public void generateOutput() {
System.out.println("CSV Output Generator");
}
}
public class JSONOutputGenerator implements OutputGenerator {
public void generateOutput() {
System.out.println("JSON Output Generator");
}
}
// In Other Code, we write Output Generator like...
public class Class1 {
public void generateOutput() {
// Here Output will be in CSV-Format, because of hard-coded code.
// This method tightly coupled with CSVOutputGenerator class, if we want another Output, we must change this method.
// Any method, that calls Class1's generateOutput will return CSVOutput, because Class1 is tight couple with CSVOutputGenerator.
OutputGenerator outputGenerator = new CSVOutputGenerator();
output.generateOutput();
}
}
Trong ví dụ trên, nếu chúng ta muốn thay đổi đầu ra trong JSON, thì chúng ta cần tìm và thay đổi toàn bộ mã, vì Class1 được kết hợp chặt chẽ với lớp CSVOutputGenerator.
public interface OutputGenerator {
public void generateOutput();
}
public class CSVOutputGenerator implements OutputGenerator {
public void generateOutput() {
System.out.println("CSV Output Generator");
}
}
public class JSONOutputGenerator implements OutputGenerator {
public void generateOutput() {
System.out.println("JSON Output Generator");
}
}
// In Other Code, we write Output Generator like...
public class Class1 {
public void generateOutput(OutputGenerator outputGenerator) {
// if you want to write JSON, pass object of JSONOutputGenerator (Dependency will be passed externally to this method)
// if you want to write CSV, pass object of CSVOutputGenerator (Dependency will be passed externally to this method)
// Due to loose couple with class, we don't need to change code of Class1, because Class1 is loose coupled with CSVOutputGenerator or JSONOutputGenerator class
// Any method, that calls Class1's generateOutput will desired output, because Class1 does not tight couple with CSVOutputGenerator or JSONOutputGenerator class
OutputGenerator outputGenerator = outputGenerator;
output.generateOutput();
}
}
Có một số công cụ cung cấp nội dung phụ thuộc thông qua thư viện của họ, ví dụ như trong .net, chúng tôi có Thư viện ninject .
Nếu bạn đang đi xa hơn trong java thì mùa xuân cung cấp khả năng này.
Các đối tượng được ghép lỏng lẻo có thể được thực hiện bằng cách giới thiệu Giao diện trong mã của bạn, đó là những gì các nguồn này làm.
Nói trong mã của bạn, bạn đang viết
Myclass m = new Myclass();
bây giờ câu lệnh này trong phương thức của bạn nói rằng bạn phụ thuộc vào myclass
điều này được gọi là kết hợp chặt chẽ. Bây giờ bạn cung cấp một số hàm xây dựng, hoặc đối tượng tiêm thuộc tính và khởi tạo đối tượng sau đó nó sẽ trở nên lỏng lẻo.
Có rất nhiều câu trả lời hay ở đây bằng cách sử dụng các phép loại suy nhưng một người bạn tại nơi làm việc đã cho tôi một ví dụ mà tôi thích hơn tất cả những câu được đề cập ở đây ... Mắt và Kính!
Khớp nối chặt chẽ
Khớp nối chặt chẽ sẽ là đôi mắt. Nếu tôi muốn khắc phục tầm nhìn của mình, tôi sẽ rất tốn kém khi được ghép mắt và chịu một rủi ro khá lớn. Nhưng điều gì sẽ xảy ra nếu nhà thiết kế (là loài người) tìm thấy một cách tốt hơn. Thêm một tính năng được kết nối lỏng lẻo với cơ thể để có thể dễ dàng thay đổi! (vâng .. kính)
Khớp nối lỏng lẻo
Tôi có thể dễ dàng thay thế kính của mình mà không phá vỡ tầm nhìn cơ bản của tôi. Tôi có thể tháo kính ra và tầm nhìn của tôi sẽ như trước đây (không tốt hơn hay tệ hơn). Sử dụng các cặp kính khác nhau sẽ thay đổi cách chúng ta nhìn thế giới qua đôi mắt với rất ít rủi ro và dễ bảo trì.
Tóm lược
Vì vậy, lần tới khi ai đó hỏi bạn "ai quan tâm liệu mã của tôi có được liên kết chặt chẽ không?" Câu trả lời là tất cả về nỗ lực thay đổi, nỗ lực duy trì và rủi ro thay đổi.
Vậy làm thế nào điều này được thực hiện trong C #? Giao diện và tiêm phụ thuộc!
BIÊN TẬP
Đây cũng là một ví dụ điển hình cho mẫu Trang trí, trong đó đôi mắt là lớp chúng ta đang trang trí bằng cách đáp ứng các yêu cầu giao diện nhưng cung cấp các chức năng khác nhau (ví dụ: kính râm, kính đọc sách, kính lúp cho thợ kim hoàn, v.v.)
Khớp nối lỏng lẻo là và trả lời cho các phụ thuộc được mã hóa kiểu cũ và các vấn đề liên quan như biên dịch lại thường xuyên khi có bất cứ điều gì thay đổi và sử dụng lại mã. Nó nhấn mạnh vào việc thực hiện logic worker trong các thành phần và tránh giải pháp cụ thể lên dây ở đó.
Loose Coupling = IoC Xem điều này để giải thích dễ dàng hơn.
Khớp nối lỏng lẻo là quá trình cung cấp sự phụ thuộc mà lớp bạn cần một cách gián tiếp mà không cung cấp tất cả thông tin của sự phụ thuộc (nghĩa là từ giao diện) trong trường hợp khớp nối chặt chẽ mà bạn cung cấp trực tiếp trong sự phụ thuộc không phải là cách mã hóa tốt.
Đó là về tỷ lệ phụ thuộc của lớp đối với các lớp khác rất thấp trong việc ghép lỏng lẻo và rất cao trong liên kết chặt chẽ. Để rõ ràng trong kiến trúc hướng dịch vụ, các dịch vụ được kết nối lỏng lẻo với nhau chống lại sự nguyên khối mà các lớp phụ thuộc vào nhau là có chủ đích
Nếu sự sáng tạo / tồn tại của một đối tượng phụ thuộc vào một đối tượng khác không thể được điều chỉnh, khớp nối chặt chẽ của nó. Và, nếu sự phụ thuộc có thể được điều chỉnh, khớp nối lỏng lẻo của nó. Hãy xem xét một ví dụ trong Java:
class Car {
private Engine engine = new Engine( "X_COMPANY" ); // this car is being created with "X_COMPANY" engine
// Other parts
public Car() {
// implemenation
}
}
Máy khách của Car
lớp có thể tạo một máy có động cơ CHỈ "X_COMPANY".
Xem xét việc phá vỡ khớp nối này với khả năng thay đổi điều đó:
class Car {
private Engine engine;
// Other members
public Car( Engine engine ) { // this car can be created with any Engine type
this.engine = engine;
}
}
Bây giờ, a Car
không phụ thuộc vào công cụ "X_COMPANY" vì nó có thể được tạo bằng các loại.
Một lưu ý cụ thể về Java: sử dụng các giao diện Java chỉ để hủy ghép nối không phải là một cách tiếp cận mong muốn thích hợp. Trong Java, một giao diện có một mục đích - hoạt động như một hợp đồng cung cấp lợi thế / hành vi không khớp nối.
Nhận xét của Bill Rosmus trong câu trả lời được chấp nhận có một lời giải thích tốt.
Khớp nối chặt chẽ có nghĩa là các lớp và các đối tượng phụ thuộc vào nhau. Nói chung, khớp nối chặt chẽ thường không tốt vì nó làm giảm tính linh hoạt và khả năng sử dụng lại mã trong khi khớp nối lỏng có nghĩa là giảm sự phụ thuộc của một lớp sử dụng trực tiếp lớp khác.
Khớp nối chặt chẽ Đối tượng được liên kết chặt chẽ là một đối tượng cần biết về các đối tượng khác và thường phụ thuộc nhiều vào giao diện của nhau. Thay đổi một đối tượng trong một ứng dụng kết hợp chặt chẽ thường yêu cầu thay đổi một số đối tượng khác. Trong các ứng dụng nhỏ, chúng ta có thể dễ dàng xác định các thay đổi và ít có cơ hội bỏ lỡ bất cứ điều gì. Nhưng trong các ứng dụng lớn, những phụ thuộc lẫn nhau này không phải lúc nào cũng được mọi lập trình viên biết đến và có cơ hội xem xét các thay đổi. Thí dụ:
class A {
public int a = 0;
public int getA() {
System.out.println("getA() method");
return a;
}
public void setA(int aa) {
if(!(aa > 10))
a = aa;
}
}
public class B {
public static void main(String[] args) {
A aObject = new A();
aObject.a = 100; // Not suppose to happen as defined by class A, this causes tight coupling.
System.out.println("aObject.a value is: " + aObject.a);
}
}
In the above example, the code that is defined by this kind of implementation uses tight coupling and is very bad since class B knows about the detail of class A, if class A changes the variable 'a' to private then class B breaks, also class A's implementation states that variable 'a' should not be more than 10 but as we can see there is no way to enforce such a rule as we can go directly to the variable and change its state to whatever value we decide.
Output
aObject.a value is: 100
Loose Coupling
Loose coupling is a design goal to reduce the inter-dependencies between components of a system with the goal of reducing the risk that changes in one component will require changes in any other component.
Loose coupling is a much more generic concept intended to increase the flexibility of the system, make it more maintainable and makes the entire framework more stable.
Example:
class A {
private int a = 0;
public int getA() {
System.out.println("getA() method");
return a;
}
public void setA(int aa) {
if(!(aa > 10))
a = aa;
}
}
public class B {
public static void main(String[] args) {
A aObject = new A();
aObject.setA(100); // No way to set 'a' to such value as this method call will
// fail due to its enforced rule.
System.out.println("aObject value is: " + aObject.getA());
}
}
Trong ví dụ trên, mã được xác định bởi loại triển khai này sử dụng khớp nối lỏng lẻo và được khuyến nghị vì lớp B phải đi qua lớp A để có được trạng thái nơi các quy tắc được thi hành. Nếu lớp A được thay đổi trong nội bộ, lớp B sẽ không bị phá vỡ vì nó chỉ sử dụng lớp A như một cách giao tiếp.
Output
getA() method
aObject value is: 0