Khớp nối lỏng lẻo là gì? Vui lòng cung cấp ví dụ


172

Tôi dường như không thể hiểu được khái niệm "khớp nối lỏng lẻo". Tôi cho rằng điều đó không giúp ích gì cho từ "lỏng lẻo" thường có ý nghĩa tiêu cực, vì vậy tôi luôn quên rằng khớp nối lỏng lẻo là một điều tốt .

Ai đó vui lòng hiển thị một số mã "trước" và "sau" (hoặc mã giả) minh họa khái niệm này?


Tôi không chắc làm thế nào điều này có thể được ly dị với một ngôn ngữ cụ thể bởi vì một phần của khái niệm là cách người ta sử dụng một ngôn ngữ để giữ cho các đơn vị mã không bị vướng mắc với nhau. Tôi cũng lưu ý rằng một số câu trả lời sử dụng mã để minh họa khái niệm này.
Onorio Catenacci

11
Không đồng ý hoàn toàn, các thực tiễn có thể được minh họa khác nhau trong các ngôn ngữ khác nhau, và nó đặc biệt rõ ràng trong các ngôn ngữ động so với các ngôn ngữ được biên dịch. Nhưng khái niệm này cũng giống nhau.
Owen

Loose vs chặt chẽkhớp nối vs tách rời . Gắn thẻ cùng không phải là một điều tốt luôn luôn, đôi khi tốt / đôi khi không tốt ... Vì chúng ta nên có sự độc lập của riêng mình, các lớp cũng vậy.
bonCodigo

Câu trả lời:


180

Hãy xem xét một ứng dụng giỏ hàng đơn giản sử dụng lớp CartContents để theo dõi các mặt hàng trong giỏ hàng và lớp Đặt hàng để xử lý mua hàng. Đơn hàng cần xác định tổng giá trị của nội dung trong giỏ hàng, nó có thể làm như vậy:

Ví dụ liên kết chặt chẽ:

public class CartEntry
{
    public float Price;
    public int Quantity;
}

public class CartContents
{
    public CartEntry[] items;
}

public class Order
{
    private CartContents cart;
    private float salesTax;

    public Order(CartContents cart, float salesTax)
    {
        this.cart = cart;
        this.salesTax = salesTax;
    }

    public float OrderTotal()
    {
        float cartTotal = 0;
        for (int i = 0; i < cart.items.Length; i++)
        {
            cartTotal += cart.items[i].Price * cart.items[i].Quantity;
        }
        cartTotal += cartTotal*salesTax;
        return cartTotal;
    }
}

Lưu ý cách phương thức OrderTotal (và do đó là lớp Order) phụ thuộc vào chi tiết triển khai của các lớp CartContents và CartEntry. Nếu chúng ta cố gắng thay đổi logic này để cho phép giảm giá, chúng ta có thể phải thay đổi cả 3 lớp. Ngoài ra, nếu chúng tôi thay đổi sử dụng bộ sưu tập Danh sách để theo dõi các mục, chúng tôi cũng sẽ phải thay đổi lớp Đơn hàng.

Bây giờ đây là một cách tốt hơn để làm điều tương tự:

Ví dụ ghép ít hơn:

public class CartEntry
{
    public float Price;
    public int Quantity;

    public float GetLineItemTotal()
    {
        return Price * Quantity;
    }
}

public class CartContents
{
    public CartEntry[] items;

    public float GetCartItemsTotal()
    {
        float cartTotal = 0;
        foreach (CartEntry item in items)
        {
            cartTotal += item.GetLineItemTotal();
        }
        return cartTotal;
    }
}

public class Order
{
    private CartContents cart;
    private float salesTax;

    public Order(CartContents cart, float salesTax)
    {
        this.cart = cart;
        this.salesTax = salesTax;
    }

    public float OrderTotal()
    {
        return cart.GetCartItemsTotal() * (1.0f + salesTax);
    }
}

Logic dành riêng cho việc triển khai chi tiết đơn hàng hoặc bộ sưu tập giỏ hàng hoặc đơn hàng được giới hạn chỉ cho lớp đó. Vì vậy, chúng ta có thể thay đổi việc thực hiện bất kỳ lớp nào trong số này mà không phải thay đổi các lớp khác. Chúng ta có thể đưa sự tách rời này đi xa hơn bằng cách cải thiện thiết kế, giới thiệu giao diện, v.v., nhưng tôi nghĩ bạn thấy rõ vấn đề.


Bạn có thể mở rộng câu trả lời giới thiệu tách rời hơn nữa thông qua tiêm phụ thuộc (mặc dù hàm tạo nên là lý tưởng)?
BAD_SEED

4
@Wedge, tôi thấy không có lý do gì Orderđể có bất kỳ kiến ​​thức nào về a Cart. Mua sắm trực tiếp và thực tế là hai bối cảnh khác nhau. Khi khách hàng sẵn sàng trả tiền, bạn có thể có một quy trình chịu trách nhiệm dịch CartEntries thành thứ gì đó có ý nghĩa cho Order. Bằng cách này, Orderlớp cũng sẽ được cung cấp và sử dụng mà không có a Cart.
plalx

@Wedge Bạn có thể phản ứng với nhận xét của tôi xin vui lòng?
plalx

Vâng & giải thích đơn giản. Tôi bắt đầu thấy ánh sáng ở ".. Chú ý phương thức OrderTotal (và do đó là lớp Order) phụ thuộc vào chi tiết triển khai của các lớp CartContents và CartEntry .."
okey_on

Ví dụ này được trình bày rõ ràng. Tuy nhiên, trong những ngày này, ngày càng có nhiều kiến ​​trúc sư đồng ý rằng phong cách hướng đối tượng quá mức này là thực tiễn xấu. Không có điểm nào trong việc che giấu các chi tiết "thực hiện" CartEntryCartContents. Vì chúng có ý nghĩa hoàn toàn rõ ràng, nên chúng được mô hình hóa đơn giản là dữ liệu chết. trong thuật ngữ Cơ sở dữ liệu, tất cả những gì cần ở đây là một bảngCREATE TABLE entry (price INTEGER, quantity INTEGER)
Jo So

160

Nhiều sản phẩm tích hợp (đặc biệt là của Apple) như iPod , iPad là một ví dụ điển hình về khớp nối chặt chẽ: một khi pin hết, bạn cũng có thể mua một thiết bị mới vì pin được hàn cố định và sẽ không bị lỏng, do đó thay thế rất nhiều đắt. Một người chơi kết hợp lỏng lẻo sẽ cho phép dễ dàng thay đổi pin.

Điều tương tự cũng xảy ra đối với phát triển phần mềm: nói chung (tốt hơn) là có mã được ghép lỏng lẻo để tạo điều kiện mở rộng và thay thế (và để làm cho các phần riêng lẻ dễ hiểu hơn). Nhưng, rất hiếm khi, trong các trường hợp đặc biệt, khớp nối chặt chẽ có thể thuận lợi vì sự tích hợp chặt chẽ của một số mô-đun cho phép tối ưu hóa tốt hơn.


Là khớp nối lỏng hay chặt là tốt? Làm thế nào để quyết định khi thực hiện khớp nối lỏng lẻo hoặc khớp nối chặt chẽ?
Saletanth Karumanaghat 14/07/2015

2
cảm ơn vì ví dụ tuyệt vời này tôi đã dành rất nhiều thời gian cho các câu trả lời khác nhưng không có giá trị như thế này
alamin

1
Saletanth Karumanaghat, bạn có muốn tiêu ít tiền hơn chỉ cho một cục pin và có một chiếc iPod hoạt động trở lại hay bạn muốn chi nhiều tiền cho cả một chiếc iPod?
Koshera

1
@SaletanthKarumanaghat Thông thường khớp nối lỏng lẻo là tốt hơn bởi vì nó thúc đẩy tính mô đun và do đó làm cho mã dễ bảo trì hơn. Nếu bạn kết hợp chặt chẽ các lớp / thư viện / mã của mình, thì bất kỳ thay đổi nhỏ nào bạn thực hiện trong một lớp sẽ phải được thực hiện trong tất cả các lớp sử dụng nó.
Kenny Worden

56

Tôi sẽ sử dụng Java làm ví dụ. Hãy nói rằng chúng ta có một lớp trông như thế này:

public class ABC
{
   public void doDiskAccess() {...}
}

Khi tôi gọi lớp, tôi sẽ cần phải làm một cái gì đó như thế này:

ABC abc = new ABC();

abc. doDiskAccess();

Càng xa càng tốt. Bây giờ hãy nói rằng tôi có một lớp khác trông như thế này:

public class XYZ
{
   public void doNetworkAccess() {...}
}

Nó trông giống hệt như ABC, nhưng giả sử nó hoạt động qua mạng thay vì trên đĩa. Vì vậy, bây giờ hãy viết một chương trình như thế này:

if(config.isNetwork()) new XYZ().doNetworkAccess();
else new ABC().doDiskAccess();

Điều đó làm việc, nhưng nó hơi khó sử dụng. Tôi có thể đơn giản hóa điều này với một giao diện như thế này:

public interface Runnable
{
    public void run();
}

public class ABC implements Runnable
{
   public void run() {...}
}

public class XYZ implements Runnable
{
   public void run() {...}
}

Bây giờ mã của tôi có thể trông như thế này:

Runnable obj = config.isNetwork() ? new XYZ() : new ABC();

obj.run();

Xem bao nhiêu sạch hơn và đơn giản hơn để hiểu đó là? Chúng ta chỉ hiểu nguyên lý cơ bản đầu tiên của khớp nối lỏng lẻo: trừu tượng. Chìa khóa từ đây là đảm bảo rằng ABC và XYZ không phụ thuộc vào bất kỳ phương thức hoặc biến nào của các lớp gọi chúng. Điều đó cho phép ABC và XYZ là các API hoàn toàn độc lập. Hay nói cách khác, chúng được "tách rời" hoặc "ghép lỏng lẻo" từ các lớp cha.

Nhưng nếu chúng ta cần giao tiếp giữa hai người thì sao? Chà, sau đó chúng ta có thể sử dụng các khái niệm trừu tượng hơn như Mô hình sự kiện để đảm bảo rằng mã cha mẹ không bao giờ cần kết hợp với các API bạn đã tạo.


2
Ví dụ này vẫn có mức độ khớp nối khá cao. Chỉ bây giờ thay vì được ghép với một lớp duy nhất, có hai để lựa chọn. Ví dụ này giả định rằng sẽ chỉ có hai triển khai "Runnable". Trong trường hợp đó, một giao diện thậm chí không cần thiết.
Owen

Các phương thức có tên Run * và Do * này là một mùi mã lớn đối với tôi. Bạn cũng có thể tái cấu trúc điều này thành sử dụng IHandleStuff hoặc IFrobnicateThings. Runnable là xa, quá chung chung một thuật ngữ trong trường hợp này.
Nêm

8
Owen, em bé bước bạn tôi. Nếu anh ta không hiểu khớp nối, làm sao anh ta hiểu được mô hình nhà máy mua cho anh ta cái gì? Ví dụ mã này đưa anh ta đi đúng hướng. Mục đích là anh ta sẽ hiểu rõ hơn vấn đề và nhận ra làm thế nào để trừu tượng hóa việc tạo ra các đối tượng.
64BitBob

6
Điều này sẽ dễ đọc hơn nếu ABC và XYZ được đổi tên thành một cái gì đó như DiskAccessorNetworkAccessor? Tôi không biết java ...
MusiGenesis

Nó cũng sử dụng mô hình thiết kế nhà máy? Bởi vì chúng tôi đang tạo các đối tượng XYZ hoặc ABC mới tùy theo nhu cầu.
munmunbb

37

Xin lỗi, nhưng "khớp nối lỏng lẻo" không phải là vấn đề mã hóa, đó là vấn đề thiết kế. Thuật ngữ "khớp nối lỏng lẻo" có liên quan mật thiết đến trạng thái mong muốn của "sự gắn kết cao", trái ngược nhưng bổ sung.

Khớp nối đơn giản có nghĩa là các yếu tố thiết kế riêng lẻ nên được xây dựng để lượng thông tin không cần thiết họ cần biết về các yếu tố thiết kế khác bị giảm.

Sự gắn kết cao giống như "khớp nối chặt chẽ", nhưng sự gắn kết cao là trạng thái mà các yếu tố thiết kế thực sự cần biết về nhau được thiết kế để chúng phối hợp với nhau một cách sạch sẽ và thanh lịch.

Vấn đề là, một số yếu tố thiết kế nên biết chi tiết về các yếu tố thiết kế khác, vì vậy chúng nên được thiết kế theo cách đó, và không vô tình. Các yếu tố thiết kế khác không nên biết chi tiết về các yếu tố thiết kế khác, vì vậy chúng nên được thiết kế theo cách đó, một cách có chủ đích, thay vì ngẫu nhiên.

Thực hiện điều này là một bài tập cho người đọc :).


33

Mã kết hợp chặt chẽ dựa trên một triển khai cụ thể. Nếu tôi cần một danh sách các chuỗi trong mã của mình và tôi khai báo nó như thế này (bằng Java)

ArrayList<String> myList = new ArrayList<String>();

sau đó tôi phụ thuộc vào việc triển khai ArrayList.

Nếu tôi muốn thay đổi mã đó thành mã được ghép lỏng lẻo, tôi đặt tham chiếu của mình thành loại giao diện (hoặc trừu tượng khác).

List<String> myList = new ArrayList<String>();

Điều này ngăn tôi gọi bất kỳ phương thức myListnào cụ thể đối với việc triển khai ArrayList. Tôi chỉ giới hạn ở những phương thức được xác định trong giao diện Danh sách. Nếu sau này tôi quyết định rằng tôi thực sự cần một LinkedList, tôi chỉ cần thay đổi mã của mình ở một nơi, nơi tôi đã tạo Danh sách mới chứ không phải ở 100 nơi tôi đã thực hiện các cuộc gọi đến các phương thức ArrayList.

Tất nhiên, bạn có thể khởi tạo một ArrayList bằng cách sử dụng khai báo đầu tiên và hạn chế không sử dụng bất kỳ phương thức nào không phải là một phần của giao diện Danh sách, nhưng sử dụng khai báo thứ hai làm cho trình biên dịch giữ cho bạn trung thực.


Điều này hầu như không liên quan đến "khớp nối" thực sự là gì . Xem stackoverflow.com/questions/39946/coupling-and-cohesion để biết một số câu trả lời hay.
Rogério

@Rogerio: Tôi nghĩ nó liên quan. Có thể bạn đang bối rối bởi các định nghĩa khác về "khớp nối" nhưng bạn nên đọc khớp nối lỏng lẻo . "Khớp mạnh xảy ra khi một lớp phụ thuộc chứa một con trỏ trực tiếp đến một lớp cụ thể cung cấp hành vi cần thiết ... Ghép lỏng xảy ra khi lớp phụ thuộc chỉ chứa một con trỏ tới một giao diện, sau đó có thể được thực hiện bởi một hoặc nhiều lớp cụ thể . " Trong ví dụ của tôi, mã của tôi sẽ được ghép lỏng lẻo với một ArrayList thông qua giao diện Danh sách.
Lập hóa đơn cho thằn lằn

@Bill: Cảm ơn vì liên kết, nhưng bài viết đó dường như hoàn toàn không có thật với tôi. Nó xuất hiện để "diễn giải lại" các ý tưởng từ một miền khác (hành vi tổ chức), đưa ra định nghĩa về "khớp nối lỏng lẻo" trái ngược với định nghĩa cụ thể về phần mềm ban đầu của Larry Constantine: en.wikipedia.org/wiki/Coupling_(computer_science) .
Rogério

@Rogerio: Bài viết của Constantine được viết vào năm 1974. Có thể có rất nhiều diễn giải lại đã diễn ra trong 36 năm qua, nhưng tôi không nghĩ rằng bài viết Wikipedia là nguồn của nó. Ví dụ, các mẫu như Dependency Injection dựa vào các giao diện để nới lỏng khớp nối giống như tôi mô tả trong câu trả lời của mình.
Lập hóa đơn cho Thằn lằn

2
@Bill: Chắc chắn, công việc của Constantine về Thiết kế có cấu trúc là những thứ cũ, nhưng tôi không thấy bất kỳ lý do nào để vô hiệu hóa hoặc giải thích lại triệt để nó. Các khái niệm ban đầu về sự gắn kết và khớp nối là cốt lõi của Thiết kế hướng đối tượng, giống như sự kế thừa và đa hình. DI (một bài viết tốt hơn là martinfowler.com/articles/injection.html ) chỉ là một kỹ thuật cho cấu hình bên ngoài của các trình cắm (giao diện trừu tượng với các triển khai được chọn trong thời gian chạy thông qua mã cấu hình); một kỹ thuật khác là mẫu Định vị dịch vụ. DI và khớp nối là các khái niệm độc lập.
Rogério

26

Mức độ khác biệt giữa các câu trả lời ở đây cho thấy lý do tại sao nó sẽ là một khái niệm khó nắm bắt nhưng để đặt nó đơn giản như tôi có thể mô tả nó:

Để tôi biết rằng nếu tôi ném bóng cho bạn, thì bạn có thể bắt nó tôi thực sự không cần biết bạn bao nhiêu tuổi. Tôi không cần biết bạn đã ăn gì vào bữa sáng, và tôi thực sự không quan tâm ai là người đầu tiên của bạn. Tất cả tôi cần biết là bạn có thể bắt. Nếu tôi biết điều này, thì tôi không quan tâm nếu đó là bạn, tôi đang ném bóng cho bạn hoặc anh trai của bạn.

Với các ngôn ngữ không động như c # hoặc Java, v.v., chúng tôi thực hiện việc này thông qua Giao diện. Vì vậy, hãy nói rằng chúng ta có giao diện sau:

public ICatcher
{
   public void Catch();
}

Và bây giờ hãy nói rằng chúng ta có các lớp sau:

public CatcherA : ICatcher
{
   public void Catch()
   {
      console.writeline("You Caught it");
   }

}
public CatcherB : ICatcher
{
   public void Catch()
   {
      console.writeline("Your brother Caught it");
   }

}

Bây giờ, cả CatchA và CatchB đều thực hiện phương thức Catch, do đó, dịch vụ yêu cầu một Catch có thể sử dụng một trong hai phương thức này và không thực sự đưa ra một cái chết tiệt nào. Vì vậy, một dịch vụ kết hợp chặt chẽ có thể trực tiếp kích hoạt một sản phẩm bị bắt

public CatchService
{
   private CatcherA catcher = new CatcherA();

   public void CatchService()
   {
      catcher.Catch();
   }

}

Vì vậy, CatchService có thể thực hiện chính xác những gì nó đã đặt ra, nhưng nó sử dụng CatchA và sẽ luôn sử dụng CatchA. Nó cứng mã hóa, vì vậy nó ở đó cho đến khi có người đi cùng và tái cấu trúc nó.

Bây giờ hãy thực hiện một tùy chọn khác, được gọi là tiêm phụ thuộc:

public CatchService
{
   private ICatcher catcher;

   public void CatchService(ICatcher catcher)
   {
      this.catcher = catcher;
      catcher.Catch();
   }
}

Vì vậy, các calss khởi tạo CatchService có thể làm như sau:

CatchService catchService = new CatchService(new CatcherA());

hoặc là

CatchService catchService = new CatchService(new CatcherB());

Điều này có nghĩa là dịch vụ Catch không được kết hợp chặt chẽ với CatchA hoặc CatchB.

Có một số chiến lược khác cho các dịch vụ ghép lỏng lẻo như thế này, chẳng hạn như việc sử dụng khung IoC, v.v.


1
Tôi thích ví dụ này tốt hơn những ví dụ khác, vì loại điều này xảy ra trong thế giới kinh doanh hàng ngày. Nếu Class Person chạy, Class Cat chạy, Class Dog chạy, v.v. Đó sẽ là một chương trình lớn để chi tiết tất cả các lớp chạy. Nhưng việc sử dụng một giao diện được gọi là chạy, trong đó mỗi lớp thực hiện cùng một việc, làm cho chương trình của bạn linh hoạt và dễ quản lý hơn nhiều. :)
sksallaj

Giải thích thực sự tốt thưa ông, chỉ cần làm rõ trong ví dụ cuối cùng bạn đã làm điều đó bằng cách tiêm phụ thuộc, và ví dụ đầu tiên cũng được ghép lỏng lẻo?
Ali Sajid

Wow, câu trả lời cũ nhận xét về :). Vì vậy, câu trả lời là không, ví dụ đầu tiên có sự phụ thuộc lớn vào CatchA để chúng được ghép nối mạnh mẽ
Owen

23

Bạn có thể nghĩ về việc ghép (chặt hoặc lỏng) theo nghĩa đen là lượng nỗ lực cần thiết để bạn tách một lớp cụ thể khỏi sự phụ thuộc của nó vào lớp khác. Ví dụ, nếu mọi phương thức trong lớp của bạn cuối cùng cũng bị chặn ở phía dưới nơi bạn thực hiện cuộc gọi đến Log4Net để ghi nhật ký, thì bạn sẽ nói rằng lớp của bạn được liên kết chặt chẽ với Log4Net. Thay vào đó, nếu lớp của bạn chứa một phương thức riêng có tên là LogS Something, nơi duy nhất được gọi là thành phần Log4Net (và các phương thức khác được gọi là LogS Something thay thế), thì bạn sẽ nói rằng lớp của bạn được ghép lỏng lẻo với Log4Net (vì nó sẽ không mất nhiều nỗ lực để kéo Log4Net ra và thay thế nó bằng một cái gì đó khác).


1
Vì vậy, "liên kết lỏng lẻo" thực sự có nghĩa là phụ thuộc ít hơn? Tôi có đúng không?
dùng314362

4
Nó không thực sự liên quan đến tổng số phụ thuộc mà một lớp cụ thể có. Khớp nối (chặt chẽ hoặc lỏng lẻo) thực sự là một tài sản của mối quan hệ giữa hai lớp. Vì vậy, bạn có thể có một lớp được ghép lỏng lẻo với 100 lớp khác hoặc một lớp khác được liên kết chặt chẽ với chỉ 2 lớp khác (ví dụ).
MusiGenesis

2
Ví dụ xấu, tôi sẽ nói: những gì bạn có là sao chép mã, không khớp nối chặt chẽ. Và với một công cụ tái cấu trúc tốt, việc sao chép như vậy có thể được loại bỏ trong vài giây.
Rogério

@Rogerio: có lẽ nó không phải là ví dụ tốt nhất. Bản thân tôi thích 64BitBobcâu trả lời hơn.
MusiGenesis

12

Định nghĩa

Về cơ bản, khớp nối là bao nhiêu một đối tượng nhất định hoặc tập hợp đối tượng dựa vào một đối tượng khác hoặc một tập hợp các đối tượng khác để hoàn thành nhiệm vụ của nó.

Khớp nối cao

Hãy nghĩ về một chiếc xe hơi. Để động cơ khởi động, một chìa khóa phải được đưa vào đánh lửa, bật, phải có xăng, phải có tia lửa, pít-tông phải bắn và động cơ phải sống. Bạn có thể nói rằng một động cơ xe hơi được kết hợp với một số đối tượng khác. Đây là khớp nối cao, nhưng nó không thực sự là một điều xấu.

Khớp nối lỏng lẻo

Hãy nghĩ về điều khiển người dùng cho một trang web chịu trách nhiệm cho phép người dùng đăng, chỉnh sửa và xem một số loại thông tin. Điều khiển duy nhất có thể được sử dụng để cho phép người dùng đăng một thông tin mới hoặc chỉnh sửa một thông tin mới. Kiểm soát có thể được chia sẻ giữa hai đường dẫn khác nhau - mới và chỉnh sửa. Nếu điều khiển được viết theo cách nó cần một số loại dữ liệu từ các trang sẽ chứa nó, thì bạn có thể nói rằng nó được ghép quá cao. Kiểm soát không cần bất cứ điều gì từ trang container của nó.


7

Đây là một khái niệm khá chung chung, vì vậy các ví dụ mã sẽ không đưa ra toàn bộ bức tranh.

Một anh chàng ở đây làm việc đã nói với tôi, "các mẫu giống như các mảnh nhỏ, bạn có thể nhìn thấy chúng khi bạn phóng to thật gần và khi bạn phóng to đến mức kiến ​​trúc."

Đọc trang wikipedia ngắn gọn có thể cho bạn cảm giác về sự chung chung này:

http://en.wikipedia.org/wiki/Loose_coupling

Theo như một ví dụ mã cụ thể ...

Đây là một khớp nối lỏng lẻo mà tôi đã làm việc gần đây, từ công cụ Microsoft.Practices.Comp cùngUI.

    [ServiceDependency]
    public ICustomizableGridService CustomizableGridService
    {
        protected get { return _customizableGridService; }
        set { _customizableGridService = value; }
    }

Mã này đang tuyên bố rằng lớp này có sự phụ thuộc vào CustomizableGridService. Thay vì chỉ tham khảo trực tiếp việc triển khai chính xác dịch vụ, nó chỉ đơn giản nói rằng nó yêu cầu MỘT SỐ triển khai dịch vụ đó. Sau đó, tại thời gian chạy, hệ thống giải quyết sự phụ thuộc đó.

Nếu điều đó không rõ ràng, bạn có thể đọc một lời giải thích chi tiết hơn ở đây:

http://en.wikipedia.org/wiki/Dependency_injection

Hãy tưởng tượng rằng ABCCustomizableGridService là sự bổ sung mà tôi dự định sẽ kết nối ở đây.

Nếu tôi chọn, tôi có thể rút nó ra và thay thế nó bằng XYZCustomizableGridService hoặc StubCustomizableGridService mà không thay đổi gì với lớp có phụ thuộc này.

Nếu tôi đã trực tiếp tham chiếu ABCCustomizableGridService, thì tôi sẽ cần thực hiện các thay đổi đối với / các tham chiếu / s đó để trao đổi trong việc triển khai dịch vụ khác.


6

Việc ghép nối phải được thực hiện với các phụ thuộc giữa các hệ thống, có thể là các mô-đun mã (hàm, tệp hoặc lớp), các công cụ trong một đường ống, quy trình máy chủ-máy khách, v.v. Các phụ thuộc càng ít chung chung, chúng càng trở nên "liên kết chặt chẽ" hơn, vì việc thay đổi một hệ thống yêu cầu thay đổi các hệ thống khác dựa vào nó. Tình huống lý tưởng là "khớp nối lỏng lẻo" trong đó một hệ thống có thể được thay đổi và các hệ thống tùy thuộc vào nó sẽ tiếp tục hoạt động mà không cần sửa đổi.

Cách chung để đạt được khớp nối lỏng lẻo là thông qua các giao diện được xác định rõ. Nếu sự tương tác giữa hai hệ thống được xác định rõ ràng và được tuân thủ ở cả hai bên, thì việc sửa đổi một hệ thống sẽ trở nên dễ dàng hơn trong khi đảm bảo rằng các quy ước không bị phá vỡ. Nó thường xảy ra trong thực tế rằng không có giao diện được xác định rõ được thiết lập, dẫn đến một thiết kế cẩu thả và khớp nối chặt chẽ.

Vài ví dụ:

  • Ứng dụng phụ thuộc vào một thư viện. Theo khớp nối chặt chẽ, ứng dụng phá vỡ các phiên bản mới hơn của lib. Google cho "Địa ngục DLL".

  • Ứng dụng khách đọc dữ liệu từ máy chủ. Theo khớp nối chặt chẽ, các thay đổi đối với máy chủ yêu cầu sửa lỗi ở phía máy khách.

  • Hai lớp tương tác trong một hệ thống phân cấp hướng đối tượng. Theo khớp nối chặt chẽ, các thay đổi đối với một lớp yêu cầu lớp khác phải được cập nhật để phù hợp.

  • Nhiều công cụ dòng lệnh giao tiếp trong một đường ống. Nếu chúng được kết hợp chặt chẽ, các thay đổi đối với phiên bản của một công cụ dòng lệnh sẽ gây ra lỗi trong các công cụ đọc đầu ra của nó.


5

Khớp nối đề cập đến cách các lớp khác nhau chặt chẽ được kết nối với nhau. Các lớp kết hợp chặt chẽ chứa một số lượng lớn các tương tác và phụ thuộc.

Các lớp liên kết lỏng lẻo ngược lại ở chỗ các phụ thuộc của chúng đối với nhau được giữ ở mức tối thiểu và thay vào đó dựa vào các giao diện công cộng được xác định rõ ràng của nhau.

Legos, đồ chơi mà SNAP kết hợp với nhau sẽ được coi là kết hợp lỏng lẻo vì bạn có thể ghép các mảnh lại với nhau và xây dựng bất kỳ hệ thống nào bạn muốn. Tuy nhiên, một trò chơi ghép hình có những mảnh ghép được TIGHTLY. Bạn không thể lấy một mảnh từ một trò chơi ghép hình (hệ thống) và đưa nó vào một câu đố khác, bởi vì hệ thống (câu đố) phụ thuộc rất nhiều vào các mảnh rất cụ thể được xây dựng cụ thể cho thiết kế hình ảnh cụ thể đó. Các legos được xây dựng theo kiểu chung chung hơn để chúng có thể được sử dụng trong Nhà Lego của bạn hoặc trong Lego Alien Man của tôi.

Tham khảo: https://megocode3.wordpress.com/2008/02/14/coupling-and-cohesion/


4

Hai thành phần được kết hợp chặt chẽ khi chúng phụ thuộc vào việc thực hiện cụ thể của nhau.

Giả sử tôi có mã này ở đâu đó trong một phương thức trong lớp:

this.some_object = new SomeObject();

Bây giờ lớp học của tôi phụ thuộc vào someObject và chúng được ghép nối cao. Mặt khác, giả sử tôi có một phương thức MethSomeObject:

void InjectSomeObject(ISomeObject so) { // note we require an interface, not concrete implementation
  this.some_object = so;
}

Sau đó, ví dụ đầu tiên chỉ có thể sử dụng someObject được tiêm. Điều này rất hữu ích trong quá trình thử nghiệm. Với hoạt động bình thường, bạn có thể sử dụng các lớp nặng, sử dụng cơ sở dữ liệu, sử dụng mạng, v.v. trong khi để kiểm tra vượt qua việc thực hiện giả, nhẹ.Với mã kết hợp chặt chẽ, bạn không thể làm điều đó.

Bạn có thể làm cho một số phần của công việc này dễ dàng hơn bằng cách sử dụng các thùng chứa phụ thuộc. Bạn có thể đọc thêm về DI tại Wikipedia: http://en.wikipedia.org/wiki/Dependency_injection .

Đôi khi dễ dàng để đưa điều này quá xa. Tại một số điểm bạn phải làm cho mọi thứ cụ thể, hoặc chương trình của bạn sẽ ít đọc và dễ hiểu hơn. Vì vậy, sử dụng kỹ thuật này chủ yếu ở ranh giới thành phần, và biết những gì bạn đang làm. Hãy chắc chắn rằng bạn đang tận dụng lợi thế của khớp nối lỏng lẻo. Nếu không, có lẽ bạn không cần nó ở nơi đó. DI có thể làm cho chương trình của bạn phức tạp hơn. Hãy chắc chắn rằng bạn thực hiện một sự đánh đổi tốt. Nói cách khác, duy trì sự cân bằng tốt. Như mọi khi khi thiết kế hệ thống. Chúc may mắn!


3

Hãy xem xét một ứng dụng Windows với FormA và FormB. FormA là hình thức chính và nó hiển thị FormB. Hãy tưởng tượng FormB cần truyền dữ liệu về cho cha mẹ của nó.

Nếu bạn đã làm điều này:

class FormA 
{
    FormB fb = new FormB( this );

    ...
    fb.Show();
}

class FormB 
{
    FormA parent;

    public FormB( FormA parent )
    {
        this.parent = parent;
    }     
}

FormB được liên kết chặt chẽ với FormA. FormB không thể có cha mẹ nào khác ngoài FormA.

Mặt khác, nếu bạn đã FormB xuất bản một sự kiện và FormA đăng ký sự kiện đó, thì FormB có thể đẩy dữ liệu trở lại thông qua sự kiện đó cho bất kỳ người đăng ký nào mà sự kiện đó có. Trong trường hợp này sau đó, FormB thậm chí không biết nói lại với cha mẹ của mình; thông qua khớp nối lỏng lẻo, sự kiện này chỉ đơn giản là nói chuyện với người đăng ký. Bất kỳ loại nào bây giờ có thể là cha mẹ của FormA.

rp


3

Trong khoa học máy tính có một ý nghĩa khác cho "khớp nối lỏng lẻo" mà không ai khác đã đăng ở đây, vì vậy ... Đây là - hy vọng bạn sẽ cho tôi một số phiếu bầu để điều này không bị mất ở cuối đống! TỰ TIN chủ đề câu trả lời của tôi thuộc về bất kỳ câu trả lời toàn diện nào cho câu hỏi ... Để dí dỏm:

Thuật ngữ "Loose Coupling" lần đầu tiên được đưa vào điện toán như một thuật ngữ được sử dụng như một tính từ liên quan đến kiến ​​trúc CPU trong cấu hình đa CPU. Thuật ngữ đối tác của nó là "khớp nối chặt chẽ". Khớp nối lỏng lẻo là khi CPU không chia sẻ nhiều tài nguyên chung và Khớp nối chặt chẽ là khi chúng thực hiện.

Thuật ngữ "hệ thống" có thể gây nhầm lẫn ở đây vì vậy hãy phân tích tình huống cẩn thận.

Thông thường, nhưng không phải lúc nào cũng vậy, nhiều CPU trong cấu hình phần cứng mà chúng tồn tại trong một hệ thống (như trong các hộp "PC" riêng lẻ) sẽ được kết hợp chặt chẽ. Ngoại trừ một số hệ thống hiệu năng siêu cao có các hệ thống con thực sự chia sẻ bộ nhớ chính trên các "hệ thống", tất cả các hệ thống chia đều được ghép lỏng lẻo.

Các thuật ngữ Kết hợp chặt chẽ và Ghép đôi lỏng lẻo đã được giới thiệu trước đây CPU đa luồng và đa lõi được phát minh, vì vậy những thuật ngữ này có thể cần một số bạn đồng hành để thể hiện đầy đủ tình huống hiện nay. Và, thực sự, ngày nay người ta rất có thể có một hệ thống bao gồm cả hai loại trong một hệ thống tổng thể. Về các hệ thống phần mềm hiện tại, có hai kiến ​​trúc phổ biến, một trong mỗi loại, đủ phổ biến, chúng nên là familliar.

Đầu tiên, vì đó là câu hỏi liên quan đến vấn đề gì, một số ví dụ về các hệ thống Loosely Coupling:

  • VaxCluster
  • Các cụm Linux

Ngược lại, một số ví dụ liên kết chặt chẽ:

  • Hệ điều hành đa chủng loại (SMP) - ví dụ Fedora 9
  • CPU đa luồng
  • CPU đa lõi

Trong điện toán ngày nay, các ví dụ về cả hai hoạt động trong một hệ thống tổng thể duy nhất không phải là hiếm. Ví dụ: lấy CPU lõi kép hoặc lõi tứ Pentium hiện đại chạy Fedora 9 - đây là những hệ thống máy tính được kết hợp chặt chẽ. Sau đó, kết hợp một vài trong số chúng trong một cụm Linux được ghép lỏng lẻo và bây giờ bạn có cả máy tính được kết nối lỏng lẻo và chặt chẽ đang diễn ra! Ồ, không phải là phần cứng hiện đại tuyệt vời!


3

Trong ngôn ngữ đơn giản, kết hợp lỏng lẻo có nghĩa là nó không phụ thuộc vào sự kiện khác xảy ra. Nó thực thi độc lập.


1
Điều đó không thực sự đúng - như đã đề cập trong các ví dụ khác, nó không liên quan nhiều đến việc có hay không có mối quan hệ giữa các thực thể (mô-đun, lớp), nhưng liệu chúng có thể dễ dàng hoán đổi cho các lớp khác thực hiện cùng chức năng hay không. ví dụ: ViewModel có thể hoạt động với các mô hình khác nhau, nhưng nó chắc chắn sẽ không hoạt động nếu không có một
Hayden Crocker

eh, không hữu ích lắm
bạn

2

Một số câu trả lời dài ở đây. Nguyên tắc là rất đơn giản mặc dù. Tôi gửi tuyên bố mở đầu từ wikipedia :

"Khớp nối lỏng lẻo mô tả mối quan hệ kiên cường giữa hai hoặc nhiều hệ thống hoặc tổ chức có mối quan hệ trao đổi nào đó.

Mỗi đầu của giao dịch làm cho các yêu cầu của nó rõ ràng và đưa ra một vài giả định về đầu kia. "


1
Nếu nó đơn giản như vậy, chúng ta sẽ không có cuộc thảo luận này.
brgs

2

Tôi đề xuất một thử nghiệm rất đơn giản về khớp nối mã :

  1. Đoạn mã A được liên kết chặt chẽ với Đoạn mã B nếu có bất kỳ sửa đổi nào có thể xảy ra đối với Đoạn B sẽ buộc các thay đổi trong Đoạn A để giữ tính chính xác.

  2. Đoạn mã A không được kết hợp chặt chẽ với Đoạn mã B nếu không có sự sửa đổi nào đối với Đoạn B có thể thay đổi thành Đoạn A cần thiết.

Điều này sẽ giúp bạn xác minh có bao nhiêu khớp nối giữa các đoạn mã của bạn. để biết lý do, hãy xem bài đăng trên blog này: http://marekdec.wordpress.com/2012/11/14/loose-coupling-tight-coupling-decoupling-what-is-that-all-about/


2

Khi bạn tạo một đối tượng của một lớp bằng cách sử dụng newtừ khóa trong một số lớp khác, bạn thực sự đang thực hiện khớp nối chặt chẽ (thực hành xấu) thay vào đó bạn nên sử dụng khớp nối lỏng lẻo, đó là một cách thực hành tốt

--- A.java ---

package interface_package.loose_coupling;

public class A {

void display(InterfaceClass obji)
{
    obji.display();
    System.out.println(obji.getVar());
}
}

--- B.java ---

package interface_package.loose_coupling;

public class B implements InterfaceClass{

private String var="variable Interface";

public String getVar() {
    return var;
}

public void setVar(String var) {
    this.var = var;
}

@Override
public void display() {
    // TODO Auto-generated method stub
    System.out.println("Display Method Called");
}
}

--- Giao diện kính ---

package interface_package.loose_coupling;

public interface InterfaceClass {

void display();
String getVar();
}

---Lớp chính---

package interface_package.loose_coupling;

public class MainClass {

public static void main(String[] args) {
    // TODO Auto-generated method stub

    A obja=new A();
    B objb=new B();
    obja.display(objb);     //Calling display of A class with object of B class 

}
}

Giải trình:

Trong ví dụ trên, chúng ta có hai lớp A và B

Lớp B thực hiện Giao diện tức là InterfaceClass.

InterfaceClass định nghĩa Hợp đồng cho lớp B là InterfaceClass có các phương thức trừu tượng của lớp B có thể được truy cập bởi bất kỳ lớp nào khác, ví dụ A.

Trong lớp A, chúng ta có phương thức hiển thị có thể ngoại trừ đối tượng của lớp thực hiện InterfaceClass (trong trường hợp của chúng ta là lớp B). Và trên phương thức đối tượng đó của lớp A đang gọi display () và getVar () của lớp B

Trong MainClass chúng ta đã tạo đối tượng của Class A và B. Và gọi phương thức hiển thị của A bằng cách truyền đối tượng của lớp B tức là objb. Phương thức hiển thị của A sẽ được gọi với đối tượng của lớp B.

Bây giờ nói về khớp nối lỏng lẻo. Giả sử trong tương lai bạn phải đổi tên Lớp B thành ABC thì bạn không phải thay đổi tên của nó trong phương thức hiển thị của lớp B, chỉ cần tạo đối tượng của lớp mới (lớp ABC) và chuyển nó sang phương thức hiển thị trong MailClass. Bạn không phải thay đổi bất cứ điều gì trong lớp A

ref: http://p3lang.com/2013/06/loose-coupling-example-USE-interface/


0

Bạn có thể đọc thêm về khái niệm chung về "khớp nối lỏng lẻo" .

Nói tóm lại, đó là một mô tả về mối quan hệ giữa hai lớp, trong đó mỗi lớp biết rất ít về lớp kia và mỗi lớp có khả năng tiếp tục hoạt động tốt dù người kia có mặt hay không và không phụ thuộc vào việc thực hiện cụ thể của lớp kia lớp học.


-8

Khớp nối lỏng lẻo, nói chung, là 2 diễn viên làm việc độc lập với nhau trên cùng một khối lượng công việc. Vì vậy, nếu bạn có 2 máy chủ web sử dụng cùng một cơ sở dữ liệu phụ trợ, thì bạn sẽ nói rằng các máy chủ web đó được kết nối lỏng lẻo. Khớp nối chặt chẽ sẽ được minh họa bằng cách có 2 bộ xử lý trên một máy chủ web ... những bộ xử lý này được ghép nối chặt chẽ.

Hy vọng điều đó có ích.


1
Tôi thấy những gì bạn đang làm, nhưng vẫn không phải là một cách tốt để giải thích rằng sự gắn kết chặt chẽ là khi hai "vật" phụ thuộc lẫn nhau, so với cặp đôi lỏng lẻo khi hai "vật" tồn tại độc lập - nơi một "vật" có thể được thay đổi mà không thay đổi 'điều' khác ...
Bryan Rehbein

Steve, bạn hoàn toàn chính xác - bạn không xứng đáng với bất kỳ phiếu bầu nào. Chỉ là khán giả của bạn chưa sẵn sàng cho thuật ngữ của bạn và quá nhiều người trên trang web này có thói quen bỏ phiếu những gì họ không hiểu hoặc những gì không quen thuộc. -shrug-
Richard T

Tôi nghĩ rằng Steve đã bỏ lỡ điểm. Khớp nối lỏng lẻo không phải lúc nào cũng ám chỉ 2 diễn viên làm việc độc lập trên cùng một khối lượng công việc.
Cướp
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.