Ràng buộc sớm và muộn là gì?


77

Tôi liên tục nghe về ràng buộc sớm và muộn, nhưng tôi không hiểu chúng là gì. Tôi tìm thấy lời giải thích sau đây mà tôi không hiểu:

Liên kết sớm đề cập đến việc gán giá trị cho các biến trong thời gian thiết kế trong khi ràng buộc muộn liên quan đến việc gán giá trị cho các biến trong thời gian chạy.

Ai đó có thể vui lòng xác định hai loại ràng buộc và so sánh chúng?


1
biên dịch thời gian vs thời gian chạy.
barlop

Dưới đây là một đọc tốt về đề tài này: en.wikibooks.org/wiki/Introduction_to_Programming_Languages/...
Jay Elston

Câu trả lời:


84

Có hai khái niệm chính trong sự nhầm lẫn: ràng buộc và tải. Nó bị giới hạn bởi khái niệm DataBinding, một nơi nào đó ở giữa thường làm cả hai. Sau khi xem xét nó, tôi sẽ thêm một khái niệm nữa, để hoàn thành trifecta, công văn.

Các loại

Binding muộn : loại không xác định cho đến khi biến được thực hiện trong thời gian chạy; thường thông qua chuyển nhượng nhưng có những cách khác để ép buộc một loại; các ngôn ngữ được gõ động gọi đây là một tính năng cơ bản, nhưng nhiều ngôn ngữ được nhập tĩnh có một số phương pháp để đạt được ràng buộc muộn

Được triển khai thường sử dụng các loại động [đặc biệt], hướng nội / phản chiếu, cờ và tùy chọn trình biên dịch hoặc thông qua các phương thức ảo bằng cách mượn và mở rộng công văn động

Binding sớm : loại được biết trước khi biến được thực hiện trong thời gian chạy, thường thông qua một phương tiện khai báo tĩnh

Được thực hiện thường xuyên bằng cách sử dụng các loại nguyên thủy tiêu chuẩn

Chức năng

Công văn tĩnh : đã biết, hàm cụ thể hoặc chương trình con tại thời điểm biên dịch; nó không rõ ràng và khớp với chữ ký

Thực hiện như các hàm tĩnh; không có phương pháp nào có thể có cùng chữ ký

Công văn động : không phải là một hàm cụ thể hoặc chương trình con tại thời điểm biên dịch; được xác định bởi bối cảnh trong quá trình thực hiện. Có hai cách tiếp cận khác nhau đối với "công văn động", được phân biệt bởi thông tin theo ngữ cảnh nào được sử dụng để chọn triển khai chức năng phù hợp.

Trong đơn [ động ] công văn , chỉ có các loại trường hợp được sử dụng để xác định việc thực hiện chức năng thích hợp. Trong các ngôn ngữ gõ tĩnh, điều này có nghĩa là gì trong thực tế là kiểu thể hiện quyết định việc thực hiện phương thức nào được sử dụng bất kể kiểu tham chiếu được chỉ định khi biến được khai báo / gán. Vì chỉ có một loại duy nhất - loại của thể hiện đối tượng - được sử dụng để suy ra cách thực hiện phù hợp, nên cách tiếp cận này được gọi là "công văn đơn".

Ngoài ra còn có nhiều [ động ] văn , nơi các loại tham số đầu vào cũng giúp xác định chức năng thực hiện để gọi. Bởi vì nhiều loại - cả loại thể hiện loại (các) tham số - ảnh hưởng đến việc thực hiện phương thức nào được chọn, phương pháp này được gọi là "nhiều công văn".

Được thực hiện như các chức năng ảo hoặc trừu tượng; các manh mối khác bao gồm các phương thức bị ghi đè, ẩn hoặc bị che khuất.

Lưu ý: Việc quá tải phương thức có liên quan đến công văn động hay không là ngôn ngữ cụ thể. Ví dụ, trong Java, các phương thức quá tải được gửi tĩnh.

Giá trị

Lazy Loading : chiến lược khởi tạo đối tượng trì hoãn việc gán giá trị cho đến khi cần ; cho phép một đối tượng ở trạng thái cơ bản hợp lệ nhưng không đầy đủ và chờ đợi cho đến khi dữ liệu cần thiết trước khi tải nó; thường được tìm thấy đặc biệt hữu ích để tải các bộ dữ liệu lớn hoặc chờ đợi trên các tài nguyên bên ngoài

Được triển khai thường xuyên bằng cách cố tình không tải một bộ sưu tập hoặc danh sách vào một đối tượng tổng hợp trong khi gọi hàm tạo hoặc khởi tạo cho đến khi một số người gọi xuôi dòng yêu cầu xem nội dung của bộ sưu tập đó (ví dụ: get_value_at, get_all_as, v.v.). Biến thể bao gồm tải thông tin meta về bộ sưu tập (như kích thước hoặc khóa), nhưng bỏ qua dữ liệu thực tế; cũng cung cấp một cơ chế cho một số thời gian chạy để cung cấp cho các nhà phát triển một kế hoạch triển khai đơn lẻ khá an toàn và hiệu quả

Tải háo hức : chiến lược khởi tạo đối tượng thực hiện ngay lập tức tất cả các phép gán giá trị để có tất cả dữ liệu cần thiết để hoàn thành trước khi xem xét bản thân ở trạng thái hợp lệ.

Được triển khai thường xuyên bằng cách cung cấp một đối tượng tổng hợp với tất cả dữ liệu đã biết càng sớm càng tốt, như trong khi gọi hàm khởi tạo hoặc khởi tạo

Liên kết dữ liệu : thường liên quan đến việc tạo một liên kết hoạt động hoặc ánh xạ giữa hai luồng thông tin tương thích để các thay đổi thành một được phản ánh trở lại vào luồng kia và ngược lại; để tương thích, họ thường phải có một loại cơ sở hoặc giao diện chung

Được triển khai thường xuyên như một nỗ lực để cung cấp đồng bộ hóa sạch hơn, nhất quán hơn giữa các khía cạnh ứng dụng khác nhau (ví dụ: mô hình xem để xem, mô hình cho bộ điều khiển, v.v.) và nói về các khái niệm như nguồn và đích, điểm cuối, liên kết / hủy liên kết, cập nhật và sự kiện như on_bind, on_property_change, on_explicit, onDef_of_scope


EDIT LƯU Ý: Chỉnh sửa lớn cuối cùng để cung cấp mô tả về các ví dụ về cách những điều này thường xảy ra. Các ví dụ mã cụ thể phụ thuộc hoàn toàn vào việc triển khai / thời gian chạy / nền tảng


2
Câu trả lời này dường như quá cụ thể đối với các ngôn ngữ hướng đối tượng.
Jack

27

Bất cứ điều gì được quyết định bởi trình biên dịch trong khi biên dịch đều có thể được tham khảo Binding EARLY / COMPILE TIME Binding và bất cứ điều gì được quyết định tại RUNTIME đều được gọi là ràng buộc LATE / RUNTIME .

Ví dụ,

Phương pháp quá tải và phương pháp ghi đè .

1) Trong Phương thức Quá tải, các phương thức của bạn gọi đến các phương thức được trình biên dịch quyết định theo nghĩa là hàm nào sẽ được gọi là do trình biên dịch của bạn quyết định tại thời điểm biên dịch. Do đó, SỚM CÀNG SỚM .

2) Trong phương thức Ghi đè, quyết định tại RUNTIME, phương thức nào sẽ được gọi. Vì vậy, nó được giới thiệu là LATE BINDING .

Đã cố gắng để giữ cho nó đơn giản và dễ dàng để có được. Hi vọng điêu nay co ich.


9

Liên kết muộn là khi hành vi được đánh giá trong thời gian chạy. Điều đó là cần thiết khi bạn thực sự muốn xác định cách hành động dựa trên thông tin bạn chỉ có khi chương trình đang chạy. Ví dụ rõ ràng nhất theo tôi là cơ chế chức năng ảo, cụ thể là trong C ++.

class A
{
public:
    void f() {}
    virtual void g() {}
};

class B : public A
{
    void f() {}
    virtual void g() {}
};

int main()
{
    A* a = new B;
    a->f();
    a->g();
}

Trong ví dụ này, a->f()sẽ thực sự gọi void A::f(), bởi vì nó bị ràng buộc sớm (hoặc tĩnh), và vì vậy chương trình trong thời gian chạy nghĩ rằng nó chỉ là một con trỏ tới một Abiến kiểu, trong khi a->g()thực tế sẽ gọi void B::g(), bởi vì trình biên dịch, nhìn thấy g()là ảo, tiêm mã để xem lên địa chỉ của hàm đúng để gọi lúc chạy.


1
"Thời gian chạy"? Bạn đang nói về C ++. C ++ biên dịch thẳng vào mã máy, nó không cần thời gian chạy để giải quyết các phương thức ảo.
tdammers

3
@tdammers C ++ thực sự cần một thư viện thời gian chạy, mặc dù không phải cho các cuộc gọi ảo. Nếu bạn đọc kỹ, bạn sẽ nhận thấy rằng câu trả lời này cho biết trình biên dịch "tiêm mã để tìm địa chỉ của hàm chính xác [...] khi chạy".

Chà, nhưng "mã để tìm địa chỉ của hàm chính xác" về cơ bản chỉ là một phép bổ trợ con trỏ hai giai đoạn không xác định theo sau là một lệnh gọi hàm. Không có "suy nghĩ" liên quan; lý do duy nhất nó hoạt động đáng tin cậy là vì trình biên dịch thực hiện kiểm tra kiểu tại thời gian biên dịch ; tại thời gian chạy, mã được tạo tin tưởng trình biên dịch đã thực hiện bài tập về nhà kiểm tra kiểu. Nếu bạn sử dụng các phôi không an toàn (ví dụ: phôi con trỏ kiểu C), bạn có thể coi các đối tượng C ++ là đối tượng của lớp sai, nhưng vtables của chúng sẽ bị rối hoàn toàn và mã chỉ bị hỏng.
tdammers

@tdammers Tôi đã cố gắng tránh xa câu trả lời đó, bởi vì đó là chi tiết triển khai của trình biên dịch, có thể hoặc không đúng với một số trình biên dịch bí truyền. Vấn đề là khái niệm.
Yam Marcovic

1
@tdammers Và theo "thời gian chạy" Ý tôi là "chương trình lúc chạy". Rõ ràng C ++ không được quản lý. Nhưng vì bạn đã cho tôi thấy nó có thể gây nhầm lẫn, tôi đang thay đổi nó thành từ ngữ đầy đủ.
Yam Marcovic

5

nếu bạn quen thuộc với các con trỏ hàm thì đây sẽ là một ví dụ. Các chức năng được xác định có thể nói là ràng buộc sớm. trong khi đó nếu bạn sử dụng chức năng con trỏ Binding muộn của nó.

  int add(int x,int y)
  {
    return x+y;
  }
  int sub(int x,int y)
  {
      return x-y;
  }


    int main()
    {
     //get user choice
     int(*fp)(int,int);
     //if add
      fp=add;
     //else if sub
     fp=sub;
     cout<<fp(2,2);
    }

ở đây các hàm add và sub là các hàm (địa chỉ của nó được liên kết tại trình biên dịch liên kết thời gian)

nhưng con trỏ hàm bị ràng buộc muộn, fp có thể gọi thêm hoặc phụ tùy theo lựa chọn của người dùng [lúc chạy].


3

Ràng buộc sớm và muộn chỉ có ý nghĩa trong bối cảnh của các loại và không phải là cách bạn đang mô tả nó. Khá nhiều ngôn ngữ hiện đại được gõ theo nghĩa là tất cả các giá trị đều có kiểu cố định. Sự khác biệt xuất hiện khi chúng ta xem xét các ngôn ngữ được gõ động và tĩnh. Trong các ngôn ngữ được gõ động, các biến không có loại để chúng có thể tham chiếu đến các giá trị thuộc bất kỳ loại nào và điều này có nghĩa là khi bạn gọi một phương thức trên một đối tượng được tham chiếu bởi một số biến, cách duy nhất để xác định xem cuộc gọi đó có hợp lệ hay không tra cứu lớp cho đối tượng và xem phương thức đó có thực sự tồn tại không. Điều này cho phép một số thứ hay ho như thêm các phương thức mới vào các lớp trong thời gian chạy vì quá trình tra cứu phương thức thực tế được hoãn lại cho đến giây phút cuối cùng. Hầu hết mọi người gọi tình trạng này là ràng buộc muộn.

Trong một biến ngôn ngữ gõ tĩnh có các loại và một khi được khai báo không thể tham chiếu đến bất kỳ giá trị nào không cùng loại. Điều này không hoàn toàn đúng nhưng hãy giả sử nó ngay bây giờ. Bây giờ nếu bạn biết rằng biến sẽ chỉ tham chiếu đến các giá trị của một loại cụ thể thì không có lý do nào để tìm hiểu xem một cuộc gọi phương thức có hợp lệ hay không tại thời điểm chạy vì bạn có thể xác định tính hợp lệ trước khi mã được chạy. Điều này được gọi là ràng buộc sớm.

Một ví dụ để chứng minh ràng buộc muộn trong ruby:

a = 1 # a is an integer at this point
a.succ # asking for its successor is valid

class A
  def method_a
    # some code
  end
end

a = A.new
a.method_a # this is also valid
a.succ # this is not valid


class A # we can re-open the class and add a method
  def succ
    # some more code
  end
end
a.succ # now this is valid

Chuỗi hành động trên không thể thực hiện được bằng một ngôn ngữ như Java nơi tất cả các loại được cố định trong thời gian chạy.


1

Thay vì cung cấp cho bạn một định nghĩa học thuật, tôi sẽ cố gắng chỉ cho bạn một số khác biệt bằng cách sử dụng một ví dụ trong thế giới thực bằng VBA:

Ràng buộc sớm:

Dim x As FileSystemObject
Set x = New FileSystemObject
Debug.Print x.GetSpecialFolder(0)

Điều này đòi hỏi một tham chiếu được đặt thành thành phần "Microsoft Scripting Runtime" tại thời điểm thiết kế . Nó có lợi thế là bạn nhận được một thông báo lỗi đã có trong thời gian biên dịch khi bạn có một lỗi đánh máy FileSystemObjecthoặc tên phương thức như thế nào GetSpecialFolder.

Ràng buộc muộn

Dim x As Object
Set x = CreateObject("Scripting.FileSystemObject")
Debug.Print x.GetSpecialFolder(0)

Điều này không yêu cầu phải tham chiếu trước, việc tạo cá thể và xác định kiểu sẽ chỉ xảy ra vào thời gian chạy. Trình biên dịch sẽ không khiếu nại tại thời gian biên dịch khi bạn cố gắng gọi một phương thức không tồn tại x, điều này sẽ dẫn đến lỗi thời gian chạy chỉ khi dòng cụ thể được thực thi.

Vì vậy, nhược điểm của ràng buộc muộn là bạn không có bất kỳ loại kiểm tra mạnh nào ở đây. Nhưng đó cũng là lợi thế - giả sử bạn có một thành phần tồn tại một số phiên bản và mỗi phiên bản mới hơn cung cấp một số chức năng bổ sung. (Một ví dụ trong thế giới thực là các thành phần MS Office, như giao diện COM của Excel) Liên kết muộn cho phép bạn viết mã hoạt động cùng với tất cả các phiên bản đó - trước tiên bạn có thể xác định phiên bản thành phần cụ thể và nếu bạn phát hiện ra rằng bạn có chỉ có phiên bản cũ hơn, tránh thực hiện các cuộc gọi chức năng không hoạt động với phiên bản đó.


-2

Có lẽ ví dụ phổ biến nhất về ràng buộc muộn là giải quyết các URL Internet. Nó hỗ trợ các hệ thống động và các hệ thống lớn mà không cần cố gắng liên kết và liên kết mọi trang web trên thế giới trước khi bạn có thể truy cập bất kỳ trang nào, nhưng mặt khác, nó phải chịu một số chi phí (tra cứu DNS, định tuyến IP ít hơn nhiều) khi chạy.

Theo ánh sáng đó, hầu hết các loại ràng buộc trong môi trường ngôn ngữ là sớm hay ít, tại thời gian biên dịch hoặc thời gian liên kết.

Mỗi loại đều có chi phí và lợi ích.


Bạn có thể trang web một tài liệu tham khảo cho định nghĩa ràng buộc này? Tôi chưa nghe nói về việc giải quyết các địa chỉ internet là "ràng buộc", mặc dù vì ràng buộc là hành động giải quyết tên, tôi cho rằng ai đó đã lập luận rằng khái niệm ràng buộc sớm / muộn có thể được áp dụng để giải quyết URI thành địa chỉ internet. Nhưng đây không phải là một cách giải thích phổ biến và khái niệm ràng buộc sớm / muộn có trước thời điểm máy tính thường được kết nối với internet.
Jay Elston
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.