Tại sao các trường riêng là riêng tư cho loại, không phải là trường hợp?


153

Trong C # (và nhiều ngôn ngữ khác), việc truy cập các trường riêng của các trường hợp khác cùng loại là hoàn toàn hợp pháp. Ví dụ:

public class Foo
{
    private bool aBool;

    public void DoBar(Foo anotherFoo)
    {
        if (anotherFoo.aBool) ...
    }
}

đặc tả C # (phần 3.5.1, 3.5.2) cho biết quyền truy cập vào các trường riêng là trên một loại, không phải là một thể hiện. Tôi đã thảo luận vấn đề này với một đồng nghiệp và chúng tôi đang cố gắng đưa ra lý do tại sao nó hoạt động như thế này (thay vì hạn chế quyền truy cập vào cùng một ví dụ).

Đối số tốt nhất chúng ta có thể đưa ra là về kiểm tra đẳng thức trong đó lớp có thể muốn truy cập các trường riêng để xác định đẳng thức với một thể hiện khác. Có bất kỳ lý do khác? Hoặc một số lý do vàng hoàn toàn có nghĩa là nó phải hoạt động như thế này hoặc một cái gì đó sẽ hoàn toàn không thể?


18
Những lợi ích cho sự thay thế là gì?
Jon Skeet

19
Đúng là nó không mô hình hóa thế giới thực rất tốt. Rốt cuộc, chỉ vì chiếc xe của tôi có thể báo cáo lượng xăng còn lại không có nghĩa là chiếc xe của tôi sẽ có thể cho biết MỌI chiếc xe còn lại bao nhiêu xăng. Vì vậy, vâng, về mặt lý thuyết tôi có thể thấy có quyền truy cập "trường hợp riêng". Tôi cảm thấy như tôi thực sự sẽ không bao giờ sử dụng nó bởi vì tôi sẽ lo lắng rằng trong 99% các trường hợp, tôi thực sự muốn có một ví dụ khác truy cập vào biến đó.
thủy cung

2
@Jon Vị trí được đặt cho cái gọi là 'lợi ích' là các lớp không nên biết trạng thái bên trong của một thể hiện khác - bất kể thực tế đó là cùng loại. Không phải là một lợi ích cho mỗi lần nói, nhưng có lẽ có một lý do khá chính đáng để chọn cái khác và đó là những gì chúng tôi đã cố gắng tìm ra
RichK

4
Bạn luôn có thể biến biến thành một cặp đóng getter / setter, được khởi tạo trong hàm tạo, sẽ không thành công nếu điều này không giống như trong quá trình khởi tạo ...
Martin Sojka

8
Scala cung cấp các thành viên riêng tư - cùng với nhiều cấp độ truy cập khác không được tìm thấy trong Java, C # và nhiều ngôn ngữ khác. Đây là một câu hỏi hoàn toàn hợp pháp.
Bruno Reis

Câu trả lời:


73

Tôi nghĩ một lý do nó hoạt động theo cách này là vì các công cụ sửa đổi truy cập hoạt động vào thời gian biên dịch . Như vậy, việc xác định có hay không một đối tượng nhất định cũng là đối tượng hiện tại không dễ thực hiện. Ví dụ, hãy xem xét mã này:

public class Foo
{
    private int bar;

    public void Baz(Foo other)
    {
        other.bar = 2;
    }

    public void Boo()
    {
        Baz(this);
    }
}

Trình biên dịch có thể nhất thiết phải tìm ra đó otherlà thực sự this? Không phải trong mọi trường hợp. Người ta có thể lập luận rằng điều này chỉ không nên biên dịch sau đó, nhưng điều đó có nghĩa là chúng ta có một đường dẫn mã trong đó một thành viên cá thể của cá thể đúng không thể truy cập được, điều mà tôi nghĩ còn tồi tệ hơn.

Chỉ yêu cầu mức độ loại chứ không phải mức độ hiển thị của đối tượng đảm bảo rằng vấn đề có thể xử lý được, cũng như tạo ra một tình huống có vẻ như nó sẽ hoạt động thực sự hoạt động.

EDIT : Quan điểm của Danilel Hilgarth rằng lý luận này ngược có giá trị. Các nhà thiết kế ngôn ngữ có thể tạo ra ngôn ngữ họ muốn và các nhà văn biên dịch phải tuân theo nó. Điều đó đang được nói, các nhà thiết kế ngôn ngữ có một số động lực để giúp các nhà văn biên dịch dễ dàng thực hiện công việc của họ hơn. (Mặc dù trong trường hợp này, thật dễ dàng để tranh luận rằng các thành viên tư nhân sau đó chỉ có thể được truy cập thông qua this(mặc nhiên hoặc rõ ràng)).

Tuy nhiên, tôi tin rằng điều đó làm cho vấn đề trở nên rắc rối hơn mức cần thiết. Hầu hết người dùng (trong đó có tôi) sẽ thấy nó unneccessarily hạn chế nếu mã ở trên không làm việc: sau khi tất cả, đó là tôi dữ liệu tôi đang cố gắng để truy cập! Tại sao tôi phải trải qua this?

Nói tóm lại, tôi nghĩ rằng tôi có thể đã phóng đại trường hợp vì nó "khó" đối với trình biên dịch. Điều tôi thực sự muốn vượt qua là tình huống trên có vẻ như là một điều mà các nhà thiết kế muốn có công việc.


33
IMHO, lý do này là cách sai. Trình biên dịch thực thi các quy tắc của ngôn ngữ. Nó không làm cho họ. Nói cách khác, nếu các thành viên riêng là "cá nhân riêng tư" chứ không phải "loại riêng tư", trình biên dịch sẽ được thực hiện theo các cách khác, ví dụ chỉ cho phép this.bar = 2nhưng không other.bar = 2, vì othercó thể là một thể hiện khác.
Daniel Hilgarth

@Daniel Đó là một điểm tốt, nhưng như tôi đã đề cập, tôi nghĩ rằng việc hạn chế đó sẽ tồi tệ hơn việc có tầm nhìn ở cấp độ.
dlev

3
@dlev: Tôi đã không nói bất cứ điều gì về việc tôi có nghĩ các thành viên "cá nhân riêng tư" hay không là một điều tốt. :-) Tôi chỉ muốn chỉ ra rằng bạn đang tranh luận rằng việc triển khai kỹ thuật áp đặt các quy tắc của ngôn ngữ và theo tôi, lập luận này không đúng.
Daniel Hilgarth

2
@Daniel Điểm lấy. Tôi vẫn nghĩ rằng đây là một sự cân nhắc hợp lệ, mặc dù bạn tất nhiên là chính xác rằng cuối cùng các nhà thiết kế ngôn ngữ tìm ra những gì họ muốn, và các nhà văn trình biên dịch tuân thủ điều đó.
dlev

2
Tôi không nghĩ rằng đối số trình biên dịch giữ. Có những ngôn ngữ xung quanh chỉ cho phép cá nhân riêng tư (như Ruby) và cho phép riêng tư cá nhân và riêng tư theo lớp (như Eiffel). Việc tạo trình biên dịch không cần thiết khó hơn hoặc dễ hơn đối với các ngôn ngữ này. Để biết thêm thông tin, xem thêm câu trả lời của tôi xuống chủ đề.
Abel

61

Bởi vì mục đích của loại đóng gói được sử dụng trong C # và các ngôn ngữ tương tự * là để giảm sự phụ thuộc lẫn nhau của các đoạn mã khác nhau (các lớp trong C # và Java), chứ không phải các đối tượng khác nhau trong bộ nhớ.

Ví dụ, nếu bạn viết mã trong một lớp sử dụng một số trường trong một lớp khác, thì các lớp này được liên kết rất chặt chẽ. Tuy nhiên, nếu bạn đang xử lý mã trong đó bạn có hai đối tượng cùng lớp, thì không có phụ thuộc thêm. Một lớp học luôn phụ thuộc vào chính nó.

Tuy nhiên, tất cả lý thuyết về đóng gói này đều thất bại ngay khi ai đó tạo các thuộc tính (hoặc các cặp get / set trong Java) và phơi bày tất cả các trường trực tiếp, điều này làm cho các lớp được ghép nối như thể dù sao chúng cũng đang truy cập các trường.

* Để làm rõ về các loại đóng gói, xem câu trả lời tuyệt vời của Abel.


3
Tôi không nghĩ rằng nó thất bại một khi get/setphương pháp được cung cấp. Các phương thức của Accessor vẫn duy trì sự trừu tượng (người dùng không cần biết có một trường phía sau nó, hoặc trường nào có thể đứng sau thuộc tính). Ví dụ: nếu chúng ta viết một Complexlớp, chúng ta có thể hiển thị các thuộc tính để lấy / đặt tọa độ cực và một get / set khác cho tọa độ Descartes. Cái nào mà lớp sử dụng bên dưới là không xác định đối với người dùng (nó thậm chí có thể là thứ gì đó hoàn toàn khác).
Ken Wayne VanderLinde

5
@Ken: Sẽ thất bại nếu bạn cung cấp một tài sản cho mọi lĩnh vực mà bạn có mà không cần cân nhắc liệu nó có bị lộ hay không.
Goran Jovic

@Goran Mặc dù tôi đồng ý rằng điều đó không lý tưởng, nhưng nó vẫn không hoàn toàn thất bại vì các bộ truy cập get / set cho phép bạn thêm logic nếu các trường bên dưới thay đổi chẳng hạn.
ForbesLindesay

1
"Bởi vì mục đích của việc đóng gói là để giảm sự phụ thuộc lẫn nhau của các đoạn mã khác nhau" >> không. Đóng gói cũng có thể có nghĩa là đóng gói cá thể, nó phụ thuộc vào ngôn ngữ hoặc trường phái tư tưởng. Một trong những tiếng nói dứt khoát nhất trên OO, Bertrand Meyer, coi điều này thậm chí là mặc định cho private. Bạn có thể kiểm tra câu trả lời của tôi cho quan điểm của tôi về mọi thứ nếu bạn thích;).
Abel

@Abel: Tôi dựa trên câu trả lời của mình dựa trên các ngôn ngữ với đóng gói lớp vì OP đã hỏi về một trong số chúng, và thẳng thắn vì tôi biết chúng. Cảm ơn đã sửa chữa và cho thông tin thú vị mới!
Goran Jovic

49

Khá nhiều câu trả lời đã được thêm vào chủ đề thú vị này, tuy nhiên, tôi hoàn toàn không tìm thấy lý do thực sự tại sao hành vi này lại diễn ra như vậy. Hãy để tôi thử

Quay trở lại những ngày

Ở đâu đó giữa Smalltalk trong thập niên 80 và Java vào giữa những năm 90, khái niệm về hướng đối tượng đã trưởng thành. Việc che giấu thông tin, ban đầu không được coi là một khái niệm chỉ có sẵn cho OO (được đề cập đầu tiên vào năm 1978), được giới thiệu trong Smalltalk vì tất cả dữ liệu (các trường) của một lớp là riêng tư, tất cả các phương thức đều công khai. Trong nhiều phát triển mới của OO trong những năm 90, Bertrand Meyer đã cố gắng chính thức hóa phần lớn các khái niệm OO trong cuốn sách mang tính bước ngoặt Xây dựng phần mềm hướng đối tượng (OOSC) mà sau đó được coi là một tài liệu tham khảo chính xác về các khái niệm OO và thiết kế ngôn ngữ .

Trong trường hợp tầm nhìn riêng tư

Theo Meyer, một phương thức nên được cung cấp cho một nhóm các lớp xác định (trang 192-193). Điều này rõ ràng mang lại độ chi tiết ẩn rất cao, tính năng sau đây có sẵn cho classA và classB và tất cả con cháu của họ:

feature {classA, classB}
   methodName

Trong trường hợp privateanh ta nói như sau: không khai báo rõ ràng một loại là hiển thị với lớp của chính nó, bạn không thể truy cập tính năng đó (phương thức / trường) trong một cuộc gọi đủ điều kiện. Tức xlà nếu là một biến,x.doSomething() không được phép. Tất nhiên, quyền truy cập không đủ điều kiện được cho phép, bên trong lớp.

Nói cách khác: để cho phép truy cập theo một thể hiện của cùng một lớp, bạn phải cho phép phương thức truy cập theo lớp đó một cách rõ ràng. Điều này đôi khi được gọi là cá thể-riêng so với lớp-riêng.

Instance-private trong ngôn ngữ lập trình

Tôi biết ít nhất hai ngôn ngữ hiện đang sử dụng sử dụng ẩn thông tin cá nhân trái ngược với ẩn thông tin riêng tư lớp. Một là Eiffel, một ngôn ngữ được thiết kế bởi Meyer, đưa OO đến những thái cực nhất. Cái còn lại là Ruby, một ngôn ngữ phổ biến hơn nhiều hiện nay. Trong Ruby, privatecó nghĩa là: "riêng tư trong trường hợp này" .

Lựa chọn thiết kế ngôn ngữ

Nó đã được đề xuất rằng cho phép cá nhân-private sẽ khó cho trình biên dịch. Tôi không nghĩ vậy, vì nó tương đối đơn giản khi chỉ cho phép hoặc không cho phép các cuộc gọi đủ điều kiện đến các phương thức. Nếu cho một phương thức riêng tư, doSomething()được cho phép vàx.doSomething() không, thì một nhà thiết kế ngôn ngữ đã xác định hiệu quả khả năng truy cập chỉ đối tượng cho các phương thức và trường riêng.

Từ quan điểm kỹ thuật, không có lý do để chọn cách này hay cách khác (đặc biệt khi xem xét rằng Eiffel.NET có thể làm điều này với IL, ngay cả với nhiều kế thừa, không có lý do cố hữu nào để không cung cấp tính năng này).

Tất nhiên, đó là vấn đề của hương vị và như những người khác đã đề cập, khá nhiều phương pháp có thể khó viết hơn nếu không có tính năng hiển thị cấp độ của các phương thức và trường riêng.

Tại sao C # chỉ cho phép đóng gói lớp và không đóng gói cá thể

Nếu bạn xem các chủ đề internet về đóng gói cá thể (một thuật ngữ đôi khi được sử dụng để chỉ thực tế là một ngôn ngữ xác định các công cụ sửa đổi truy cập ở cấp độ cá thể, trái ngược với cấp độ lớp học), khái niệm này thường được sử dụng. Tuy nhiên, xem xét rằng một số ngôn ngữ hiện đại sử dụng đóng gói cá thể, ít nhất là cho công cụ sửa đổi truy cập riêng tư, khiến bạn nghĩ rằng nó có thể và được sử dụng trong thế giới lập trình hiện đại.

Tuy nhiên, C # đã thừa nhận là khó nhất đối với C ++ và Java về thiết kế ngôn ngữ. Trong khi Eiffel và Modula-3 cũng có mặt trong bức tranh, xem xét nhiều tính năng của Eiffel bị thiếu (nhiều kế thừa), tôi tin rằng họ đã chọn cùng một tuyến đường với Java và C ++ khi nói đến công cụ sửa đổi truy cập riêng.

Nếu bạn thực sự muốn biết lý do tại sao bạn nên cố gắng nắm giữ Eric Lippert, Krzysztof Cwalina, Anders Hejlsberg hoặc bất kỳ ai khác làm việc theo tiêu chuẩn của C #. Thật không may, tôi không thể tìm thấy một ghi chú dứt khoát trong Ngôn ngữ lập trình C # được chú thích .


1
Đó là một câu trả lời đáng yêu với nhiều thông tin cơ bản, rất thú vị, cảm ơn vì đã dành thời gian trả lời một câu hỏi cũ (tương đối)
RichK

1
@RichK: Bạn được chào đón, tôi đoán câu hỏi quá muộn, nhưng tôi thấy chủ đề đủ hấp dẫn để trả lời với một số chiều sâu :)
Abel

Trong COM, "private" có nghĩa là "thể hiện riêng tư". Tôi nghĩ rằng đây là một số biện pháp vì một định nghĩa về lớp Foothể hiện một cách hiệu quả một giao diện và một lớp thực hiện; vì COM không có khái niệm về một tham chiếu đối tượng lớp - chỉ là một tham chiếu giao diện - không có cách nào một lớp có thể giữ một tham chiếu đến một cái gì đó được đảm bảo là một thể hiện khác của lớp đó. Thiết kế dựa trên giao diện này làm cho một số thứ trở nên cồng kềnh, nhưng điều đó có nghĩa là người ta có thể thiết kế một lớp có thể thay thế cho lớp khác mà không phải chia sẻ bất kỳ nội bộ nào.
supercat

2
Câu trả lời chính xác. OP nên xem xét đánh dấu câu hỏi này câu trả lời.
Gavin Osborn

18

Đây chỉ là ý kiến ​​của tôi, nhưng thực tế, tôi nghĩ rằng nếu một lập trình viên có quyền truy cập vào nguồn của một lớp, bạn có thể tin tưởng họ một cách hợp lý với việc truy cập các thành viên riêng của cá thể lớp. Tại sao ràng buộc một lập trình viên tay phải khi ở bên trái của bạn, bạn đã trao cho họ chìa khóa của vương quốc?


13
Tôi không hiểu lập luận này. Giả sử bạn đang làm việc trên một chương trình mà bạn là nhà phát triển duy nhất và bạn là người duy nhất sẽ sử dụng thư viện của mình, bạn có nói rằng trong trường hợp đó bạn làm cho MỌI thành viên công khai vì bạn có quyền truy cập vào mã nguồn?
thủy cung

@aquinas: điều đó khá khác biệt. Làm cho mọi thứ công khai sẽ dẫn đến thực hành lập trình khủng khiếp. Cho phép một loại để xem các trường riêng của các trường hợp khác của chính nó là một trường hợp rất hẹp.
Igby Largeeman

2
Không, tôi không ủng hộ việc công khai mọi thành viên. Trời không! Lập luận của tôi là, nếu bạn đã ở trong nguồn, có thể thấy các thành viên tư nhân, cách họ được sử dụng, các quy ước được sử dụng, v.v., vậy tại sao không thể sử dụng kiến ​​thức đó?
FishBasketGordo

7
Tôi nghĩ rằng cách suy nghĩ vẫn còn trong các điều khoản của loại. Nếu loại không thể tin cậy để đối phó với các thành viên của loại đúng, thì có thể làm gì? ( Thông thường , đó sẽ là một lập trình viên thực sự kiểm soát các tương tác, nhưng trong thời đại công cụ tạo mã này, điều đó có thể không phải luôn luôn như vậy.)
Anthony Pegram

3
Câu hỏi của tôi không thực sự đáng tin cậy, cần thiết hơn. Sự tin tưởng là hoàn toàn không liên quan khi bạn có thể sử dụng sự phản ánh cho những thứ ghê tởm cho tư nhân. Tôi đang tự hỏi tại sao, về mặt khái niệm, bạn có thể truy cập các tư nhân. Tôi cho rằng có một lý do hợp lý hơn là một tình huống thực hành tốt nhất.
RichK

13

Lý do thực sự là kiểm tra bình đẳng, so sánh, nhân bản, quá tải toán tử ... Sẽ rất khó để thực hiện toán tử + trên các số phức, chẳng hạn.


3
Nhưng tất cả mọi thứ mà bạn đề cập đều yêu cầu một loại NHẬN giá trị của loại khác. Tôi ở trên tàu với câu nói: bạn muốn kiểm tra nhà nước tư nhân của tôi? Được rồi, đi tiếp. Bạn muốn thiết lập trạng thái riêng tư của tôi? Không có cách nào, bạn thân, thay đổi trạng thái chết tiệt của riêng bạn. :)
thủy cung

2
@aquinas Nó không hoạt động theo cách đó. Lĩnh vực là lĩnh vực. Chúng chỉ đọc chỉ khi được khai báo readonlyvà sau đó cũng áp dụng cho thể hiện khai báo. Rõ ràng là bạn đang khẳng định rằng cần phải có một quy tắc biên dịch cụ thể để cấm điều này, nhưng mỗi quy tắc đó là một tính năng mà nhóm C # phải chỉ ra, ghi lại, bản địa hóa, kiểm tra, duy trì và hỗ trợ. Nếu không có lợi ích hấp dẫn thì tại sao họ lại làm điều đó?
Aaronaught

Tôi đồng ý với @Aaronaught: có một chi phí liên quan đến việc thực hiện mọi thông số kỹ thuật mới và thay đổi trình biên dịch. Đối với một kịch bản được thiết lập, hãy xem xét một phương pháp Clone. Chắc chắn, bạn có thể muốn nhận ra nó với một nhà xây dựng tư nhân, nhưng có thể trong một số trường hợp không thể / không nên.
Lorenzo Dematté

1
Đội C #? Tôi chỉ đang tranh luận về những thay đổi ngôn ngữ lý thuyết có thể có trong ngôn ngữ BẤT K .. "Nếu không có lợi ích hấp dẫn ..." Tôi nghĩ có thể có một lợi ích. Giống như với bất kỳ bảo đảm trình biên dịch nào , ai đó có thể thấy hữu ích để đảm bảo rằng một lớp chỉ sửa đổi trạng thái của chính nó.
thủy cung

@aquinas: Đặc điểm nhận thực hiện vì họ hữu ích cho nhiều hoặc hầu hết người dùng - không phải vì họ có thể có ích trong một số trường hợp bị cô lập.
Aaronaught

9

Trước hết, điều gì sẽ xảy ra với các thành viên tĩnh tư nhân? Họ chỉ có thể được truy cập bằng phương pháp tĩnh? Bạn chắc chắn sẽ không muốn điều đó, bởi vì sau đó bạn sẽ không thể truy cập vào consts của bạn .

Đối với câu hỏi rõ ràng của bạn, hãy xem xét trường hợp của a StringBuilder, được triển khai như một danh sách các trường hợp được liên kết của chính nó:

public class StringBuilder
{
    private string chunk;
    private StringBuilder nextChunk;
}

Nếu bạn không thể truy cập các thành viên riêng của các phiên bản khác của lớp của riêng bạn, bạn phải thực hiện ToStringnhư sau:

public override string ToString()
{
    return chunk + nextChunk.ToString();
}

Điều này sẽ hoạt động, nhưng đó là O (n ^ 2) - không hiệu quả lắm. Trong thực tế, điều đó có thể đánh bại toàn bộ mục đích có một StringBuilderlớp học ngay từ đầu. Nếu bạn có thể truy cập các thành viên riêng của các phiên bản khác của lớp của riêng bạn, bạn có thể thực hiện ToStringbằng cách tạo một chuỗi có độ dài phù hợp và sau đó thực hiện một bản sao không an toàn của từng đoạn đến vị trí thích hợp trong chuỗi:

public override string ToString()
{
    string ret = string.FastAllocateString(Length);
    StringBuilder next = this;

    unsafe
    {
        fixed (char *dest = ret)
            while (next != null)
            {
                fixed (char *src = next.chunk)
                    string.wstrcpy(dest, src, next.chunk.Length);
                next = next.nextChunk;
            }
    }
    return ret;
}

Việc triển khai này là O (n), làm cho nó rất nhanh và chỉ có thể nếu bạn có quyền truy cập vào các thành viên riêng của các phiên bản khác của lớp .


Vâng, nhưng không có cách nào khác xung quanh đó, chẳng hạn như phơi bày một số lĩnh vực là nội bộ?
MikeKulls

2
@Mike: Phơi bày một lĩnh vực internallàm cho nó ít riêng tư hơn ! Cuối cùng, bạn sẽ tiết lộ nội bộ của lớp mình cho mọi thứ trong hội đồng của nó.
Gabe

3

Điều này là hoàn toàn hợp pháp trong nhiều ngôn ngữ (C ++ cho một). Các sửa đổi truy cập đến từ nguyên tắc đóng gói trong OOP. Ý tưởng là để hạn chế truy cập ra bên ngoài , trong trường hợp này bên ngoài là các lớp khác. Bất kỳ lớp lồng nhau nào trong C # chẳng hạn cũng có thể truy cập vào các thành viên riêng của cha mẹ.

Trong khi đây là một sự lựa chọn thiết kế cho một nhà thiết kế ngôn ngữ. Việc hạn chế quyền truy cập này có thể làm phức tạp một số tình huống rất phổ biến mà không đóng góp nhiều vào sự cô lập của các thực thể.

Có một cuộc thảo luận tương tự ở đây


1

Tôi không nghĩ rằng có một lý do chúng ta không thể thêm một mức độ riêng tư khác, trong đó dữ liệu là riêng tư cho mỗi trường hợp. Trong thực tế, điều đó thậm chí có thể cung cấp một cảm giác tốt đẹp về sự hoàn chỉnh cho ngôn ngữ.

Nhưng trong thực tế, tôi nghi ngờ nó sẽ thực sự hữu ích. Như bạn đã chỉ ra, tính riêng tư thông thường của chúng tôi rất hữu ích cho những việc như kiểm tra bình đẳng, cũng như hầu hết các hoạt động khác liên quan đến nhiều phiên bản của Loại. Mặc dù, tôi cũng thích quan điểm của bạn về việc duy trì sự trừu tượng hóa dữ liệu, vì đó là một điểm quan trọng trong OOP.

Tôi nghĩ rằng xung quanh, cung cấp khả năng hạn chế quyền truy cập theo cách như vậy có thể là một tính năng hay để thêm vào OOP. Nó thực sự hữu ích? Tôi muốn nói là không, vì một lớp sẽ có thể tin tưởng vào mã của chính nó. Vì lớp đó là thứ duy nhất có thể truy cập các thành viên tư nhân, không có lý do thực sự nào cần sự trừu tượng hóa dữ liệu khi xử lý một thể hiện của lớp khác.

Tất nhiên, bạn luôn có thể viết mã của mình như thể áp dụng riêng cho các thể hiện. Sử dụng các get/setphương pháp thông thường để truy cập / thay đổi dữ liệu. Điều đó có thể sẽ làm cho mã dễ quản lý hơn nếu lớp có thể chịu sự thay đổi bên trong.


0

Câu trả lời tuyệt vời được đưa ra ở trên. Tôi sẽ nói thêm rằng một phần của vấn đề này là việc khởi tạo một lớp bên trong chính nó thậm chí còn được cho phép ngay từ đầu. Ví dụ, nó thực hiện trong một vòng lặp "for" logic đệ quy để sử dụng loại mẹo đó miễn là bạn có logic để kết thúc đệ quy. Nhưng khởi tạo hoặc vượt qua cùng một lớp bên trong chính nó mà không tạo ra các vòng lặp như vậy một cách hợp lý sẽ tạo ra những nguy hiểm riêng của nó, mặc dù mô hình lập trình được chấp nhận rộng rãi. Ví dụ, Lớp C # có thể khởi tạo một bản sao của chính nó trong hàm tạo mặc định của nó, nhưng điều đó không phá vỡ bất kỳ quy tắc nào hoặc tạo các vòng lặp nguyên nhân. Tại sao?

BTW .... vấn đề tương tự này cũng áp dụng cho các thành viên "được bảo vệ". :

Tôi chưa bao giờ chấp nhận mô hình lập trình đó một cách đầy đủ bởi vì nó vẫn đi kèm với một loạt các vấn đề và rủi ro mà hầu hết các lập trình viên không nắm bắt được cho đến khi các vấn đề như vấn đề này xuất hiện và gây nhầm lẫn cho mọi người và bất chấp toàn bộ lý do để có thành viên riêng.

Khía cạnh "kỳ quặc và kỳ quặc" này của C # vẫn là một lý do nữa khiến lập trình tốt không liên quan gì đến kinh nghiệm và kỹ năng, mà chỉ cần biết các thủ thuật và bẫy ..... như làm việc trên xe hơi. Đối số của nó là các quy tắc có nghĩa là bị phá vỡ, đó là một mô hình rất xấu cho bất kỳ ngôn ngữ điện toán nào.


-1

Dường như với tôi rằng nếu dữ liệu là riêng tư đối với các trường hợp khác cùng loại, thì nó không nhất thiết phải cùng loại nữa. Nó dường như sẽ không cư xử hoặc hành động giống như các trường hợp khác. Hành vi có thể dễ dàng được sửa đổi dựa trên dữ liệu nội bộ riêng tư đó. Điều đó sẽ chỉ lan truyền sự nhầm lẫn trong quan điểm của tôi.

Nói một cách lỏng lẻo, cá nhân tôi nghĩ rằng các lớp viết xuất phát từ một lớp cơ sở cung cấp chức năng tương tự như bạn đang mô tả với "có dữ liệu riêng tư trên mỗi thể hiện". Thay vào đó, bạn chỉ có một định nghĩa lớp mới cho mỗi loại 'duy nhất'.

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.