Bất biến là gì, làm thế nào chúng có thể được sử dụng và bạn đã bao giờ sử dụng nó trong chương trình của mình chưa?


48

Tôi đang đọc Coders tại nơi làm việc , và trong đó có rất nhiều thảo luận về bất biến. Theo như tôi đã hiểu, bất biến là một điều kiện giữ cả trước và sau một biểu thức. Chúng, trong số những thứ khác, hữu ích trong việc chứng minh rằng vòng lặp đó là chính xác, nếu tôi nhớ chính xác khóa học Logic của mình.

Là mô tả của tôi chính xác, hoặc tôi đã bỏ lỡ một cái gì đó? Bạn đã bao giờ sử dụng chúng trong chương trình của bạn? Và nếu vậy, họ đã được lợi như thế nào?



@Robert Harvey: Vâng, tôi thực sự đã đọc nó. Nhưng dường như đối với tôi, bất biến chỉ hữu ích khi bạn cố gắng chứng minh điều gì đó. Điều này có đúng không (không có ý định chơi chữ)?
gablin

Đó là sự hiểu biết của tôi; khi bạn đang cố gắng lý luận về chương trình của bạn, để chứng minh tính đúng đắn của nó.
Robert Harvey

3
@ user9094: Một xác nhận là một tuyên bố rằng một cái gì đó là đúng tại một điểm cụ thể trong thời gian chạy và được thể hiện trong mã. Bất biến là một tuyên bố (người ta hy vọng có cơ sở) sẽ luôn luôn đúng bất cứ khi nào nó được áp dụng và không được thể hiện trong chính mã.
David Thornley

1
Bất biến thực sự hữu ích cho việc chứng minh tính đúng đắn, nhưng chúng không giới hạn trong trường hợp đó. Chúng cũng hữu ích cho lập trình phòng thủ và trong quá trình gỡ lỗi. Họ không chỉ giúp chứng minh mã của bạn là chính xác, họ giúp lý do về mã và tìm vị trí của các lỗi gần với nguồn gốc.
Oddthinking

Câu trả lời:


41

Trong OOP, bất biến là một tập hợp các xác nhận phải luôn luôn đúng trong suốt vòng đời của một đối tượng để chương trình có hiệu lực. Nó nên giữ đúng từ cuối của hàm tạo đến đầu của hàm hủy bất cứ khi nào đối tượng hiện không thực thi một phương thức thay đổi trạng thái của nó.

Một ví dụ về bất biến có thể là chính xác một trong hai biến thành viên nên là null. Hoặc nếu một cái có một giá trị nhất định, thì tập hợp các giá trị được phép cho cái kia là cái này hoặc cái kia ...

Thỉnh thoảng tôi sử dụng một hàm thành viên của đối tượng để kiểm tra xem bất biến có giữ không. Nếu đây không phải là trường hợp, một khẳng định được đưa ra. Và phương thức được gọi ở đầu và thoát của mỗi phương thức làm thay đổi đối tượng (trong C ++, đây chỉ là một dòng ...)


11
+1 để đề cập đến bất biến không cần phải đúng ở giữa phương thức thực thi.
Oddthinking

1
@Oddthinking Tốt nhất nên tránh điều đó khi có thể. Sẽ dễ dàng để vào trạng thái phá vỡ bất biến và quên khôi phục lại mọi thứ một cách chính xác trước khi quay trở lại. Ngoại lệ cũng có thể cung cấp cho bạn rắc rối.
Alexander

3
@Alexander: Đối với những bất biến không tầm thường, gần như không thể tránh được. Nếu bạn cần cập nhật nhiều hơn một biến trong một phương thức, như được mô tả trong câu trả lời, có một điểm chỉ có một biến được cập nhật và bất biến là sai. Có đủ các ràng buộc về việc viết mã tốt mà không cần thêm mã mới.
Oddthinking

@Oddthinking Vâng, nó thường không thể tránh khỏi. Nhưng ví dụ, nếu có một nhóm các biến thuộc về nhau một cách hợp lý (ví dụ: một mảng và chỉ mục của một mục "được chọn" trong mảng), thì có lẽ nên trích xuất chúng thành một loại. Từ đó, các đột biến của mảng hoặc kiểu có thể được biểu diễn dưới dạng một phép gán duy nhất của một thể hiện mới của kiểu đó
Alexander

13

Chà, những thứ tôi thấy trong chủ đề này đều tuyệt vời, nhưng tôi có một định nghĩa về một "bất biến" rất hữu ích cho tôi trong công việc.

Bất biến là bất kỳ quy tắc logic nào phải được tuân theo trong suốt quá trình thực thi chương trình của bạn có thể được truyền đạt tới người, nhưng không phải với trình biên dịch của bạn.

Định nghĩa này rất hữu ích vì nó tách ra các điều kiện thành hai nhóm: những trình biên dịch có thể được tin cậy khi thực thi và những nhóm phải được ghi lại, thảo luận, nhận xét hoặc truyền đạt tới những người đóng góp để họ tương tác với codebase mà không gây ra lỗi .

Ngoài ra, định nghĩa này rất hữu ích vì nó cho phép bạn sử dụng khái quát hóa, "Bất biến là xấu".

Ví dụ, bộ chuyển động trong một chiếc xe số tay được thiết kế để tránh bất biến. Nếu tôi muốn, tôi có thể xây dựng một hộp số với một đòn bẩy cho mỗi thiết bị. Đòn bẩy này có thể được chuyển tiếp ("tham gia") hoặc quay lại ("thảnh thơi"). Trong một hệ thống như vậy, tôi đã tạo ra một "bất biến", có thể được ghi lại như sau:

"Điều rất quan trọng là thiết bị hiện đang được tháo ra trước khi một thiết bị khác được tham gia. Để tham gia bất kỳ hai bánh răng nào cùng một lúc sẽ gây ra căng thẳng cơ học sẽ xé tan bộ truyền. Luôn luôn ngắt thiết bị hiện đang tham gia trước khi gắn thiết bị khác."

Và do đó, người ta có thể đổ lỗi cho việc truyền bị hỏng khi lái xe cẩu thả. Tuy nhiên, những chiếc xe hiện đại sử dụng một cây gậy duy nhất xoay quanh các bánh răng. Nó được thiết kế theo cách mà trên một chiếc xe sang số hiện đại, không thể tham gia hai bánh răng cùng một lúc.

Theo cách này, chúng ta có thể nói rằng việc truyền đã được thiết kế để "loại bỏ bất biến", bởi vì nó không cho phép bản thân được cấu hình cơ học theo cách vi phạm quy tắc logic.

Mọi bất biến của loại này mà bạn loại bỏ khỏi mã của mình là một sự cải tiến, bởi vì nó làm giảm tải nhận thức khi làm việc với nó.


1
Nếu bất biến là bất kỳ quy tắc logic nào phải được tuân theo trong suốt quá trình thực thi chương trình của bạn và quy tắc logic của bạn là không có hai bánh răng nào có thể được tham gia cùng một lúc, thì đó không phải là bất biến mà không có hai bánh răng nào có thể tham gia cùng một lúc thời gian? Nếu không có bất biến này, việc truyền của bạn có thể ở hai bánh răng cùng một lúc, và do đó tự xé ra. Đầu tiên, không phải là một shifter duy nhất thực sự thực thi bất biến đó sao? Thứ hai, tại sao một bất biến về bản chất là tốt hay xấu?
Dustin Cleveland

1
Sự so sánh với bánh răng của xe rất rõ ràng đối với tôi. Cảm ơn!
Marecky

"Bất biến là bất kỳ quy tắc logic nào phải được tuân theo trong suốt quá trình thực thi chương trình của bạn có thể được truyền đạt tới người, nhưng không phải với trình biên dịch của bạn." - Tôi khá thích điều này, súc tích và dễ nhớ.
ZeroKnight

@DustinCleoween Tôi nghĩ rằng trong ví dụ này, các cơ chế đằng sau sự thay đổi thanh là 'trình biên dịch' 'thực thi' các quy tắc, trong khi trình điều khiển có thể gây ra sự cố là một trong nhiều khách hàng phải sử dụng và ghi nhớ thông tin đó được "ghi lại, thảo luận, bình luận, hoặc truyền đạt."
ebernard

Giải thích tuyệt vời! Bây giờ tôi thực sự hiểu lý do tại sao có bất biến trong mã của bạn là thực tiễn xấu.
Ben C Wang

3

Một bất biến (theo cách hiểu thông thường) có nghĩa là một số điều kiện phải đúng tại một số thời điểm hoặc thậm chí luôn luôn trong khi chương trình của bạn đang thực thi. ví dụ PreConditions và PostConditions có thể được sử dụng để khẳng định một số điều kiện phải đúng khi hàm được gọi và khi nó trả về. Các bất biến đối tượng có thể được sử dụng để khẳng định rằng một đối tượng phải có trạng thái hợp lệ trong suốt thời gian nó tồn tại. Đây là thiết kế theo nguyên tắc hợp đồng.
Tôi đã sử dụng bất biến một cách không chính thức bằng cách sử dụng kiểm tra trong mã. Nhưng gần đây tôi đang chơi với thư viện hợp đồngcho .Net hỗ trợ trực tiếp các bất biến.


3

Dựa trên trích dẫn sau đây của Coders At Work ...

Nhưng một khi bạn biết bất biến mà nó đang duy trì, bạn có thể thấy, à, nếu chúng ta duy trì bất biến đó thì chúng ta sẽ có được thời gian tra cứu nhật ký.

... Tôi đoán "bất biến" = "điều kiện bạn muốn duy trì để đảm bảo hiệu quả mong muốn".

Dường như bất biến có hai giác quan khác nhau một cách tinh tế:

  1. Một cái gì đó vẫn giữ nguyên.
  2. Một cái gì đó mà bạn đang cố gắng giữ nguyên, để đạt được mục tiêu X (chẳng hạn như "thời gian tra cứu nhật ký" ở trên).

Vì vậy, 1 giống như một khẳng định; 2 giống như một công cụ để chứng minh tính đúng đắn, hiệu suất hoặc các thuộc tính khác - tôi nghĩ vậy. Xem bài viết Wikipedia để biết ví dụ về 2 (chứng minh tính đúng đắn của giải pháp cho câu đố MU).

Thật ra cảm giác bất biến thứ 3 là:

.3. Những gì chương trình (hoặc mô-đun hoặc chức năng) phải làm; nói cách khác, mục đích của nó.

Từ cùng một Coders Tại nơi phỏng vấn:

Nhưng điều làm cho phần mềm lớn có thể quản lý được là có một số bất biến toàn cầu hoặc tuyên bố lớn về những gì nó phải làm và những gì được cho là đúng.


1

Một bất biến giống như một quy tắc hoặc một giả định có thể được sử dụng để ra lệnh logic của chương trình của bạn.

Ví dụ: giả sử bạn có một số ứng dụng phần mềm theo dõi tài khoản người dùng. Giả sử người dùng cũng có thể có nhiều tài khoản, nhưng vì bất kỳ lý do gì bạn cần phân biệt giữa tài khoản chính của người dùng và tài khoản "bí danh".

Đây có thể là bản ghi DB hoặc một cái gì đó khác, nhưng bây giờ, giả sử mỗi tài khoản người dùng được đại diện bởi một đối tượng lớp.

lớp userAccount {private char * pUserName; char riêng * pParentAccountUserName;

...}

Một bất biến có thể là giả định rằng nếu pParentAccountUserName là NULL hoặc trống thì đối tượng này là tài khoản mẹ. Bạn có thể sử dụng bất biến này để phân biệt các loại tài khoản khác nhau. Có lẽ có các phương pháp tốt hơn để phân biệt các loại tài khoản người dùng khác nhau, vì vậy hãy nhớ rằng đây chỉ là một ví dụ để cho thấy cách bất biến có thể được sử dụng.


Bất biến kiểm tra trạng thái của một chương trình. Họ không quyết định thiết kế.
Xavier Nodet

3
Bất biến không kiểm tra bất cứ điều gì. Bạn có thể kiểm tra trạng thái của chương trình để xem liệu bất biến là TRUE hay FALSE, nhưng bản thân bất biến "không" làm gì.
Pemdas

2
Thông thường, trong C ++, bạn sẽ thấy một số loại bất biến lớp như thành viên x phải nhỏ hơn 25 và lớn hơn 0. Đó là bất biến. Bất kỳ kiểm tra chống lại bất biến đó là khẳng định. Trong ví dụ tôi có ở trên, bất biến của tôi là nếu pParentAccountUserName là NULL hoặc trống thì đó là tài khoản mẹ. Bất biến được quyết định thiết kế.
Pemdas

Làm thế nào để bạn kiểm tra xem nếu pParentAccountUserName là NULL hay trống thì đối tượng này là tài khoản mẹ? Tuyên bố của bạn chỉ xác định giá trị null / trống được cho là gì. Điều bất biến là hệ thống tuân thủ điều đó, tức là pParentAccountUserName chỉ có thể là rỗng hoặc trống nếu đó là tài khoản mẹ. Đó là một sự khác biệt tinh tế.
Cameron

1

Xuất phát từ một nền tảng vật lý, trong vật lý chúng ta có các bất biến, về cơ bản là các đại lượng không thay đổi trong toàn bộ tính toán / mô phỏng. Ví dụ, trong vật lý, đối với toàn bộ hệ thống năng lượng được bảo toàn. Hoặc một lần nữa trong vật lý, nếu hai hạt va chạm, các mảnh kết quả phải chứa chính xác năng lượng mà chúng bắt đầu và chính xác cùng một động lượng (một đại lượng vectơ). Thông thường không có đủ bất biến để hoàn toàn chỉ định kết quả. Ví dụ, trong vụ va chạm 2 hạt, chúng ta có bốn bất biến, ba thành phần động lượng và một thành phần năng lượng, nhưng hệ thống có sáu bậc tự do (sáu số để mô tả trạng thái của nó). Các bất biến phải được bảo toàn trong phạm vi làm tròn, nhưng bảo tồn của chúng không chứng minh được giải pháp là đúng.

Vì vậy, thông thường, những điều này rất quan trọng khi kiểm tra sự tỉnh táo, nhưng bản thân chúng không thể chứng minh tính đúng đắn.


1
-1 Bất biến trong vật lý là khác nhau. Tính toán một giải pháp không giống như chứng minh rằng một thuật toán là chính xác. Đối với cái sau, bất biến có thể chứng minh tính đúng đắn.
aaronasterling
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.