Đó là một điểm rất quan trọng, nhưng IMHO đáng để hiểu.
Tất cả các ngôn ngữ OO luôn tạo các bản sao của tài liệu tham khảo và không bao giờ sao chép một đối tượng 'vô hình'. Sẽ khó hơn nhiều để viết chương trình nếu các ngôn ngữ OO hoạt động theo bất kỳ cách nào khác. Ví dụ, các hàm và phương thức, không bao giờ có thể cập nhật một đối tượng. Java và hầu hết các ngôn ngữ OO sẽ gần như không thể sử dụng nếu không có độ phức tạp được thêm vào đáng kể.
Một đối tượng trong một chương trình được cho là có ý nghĩa. Ví dụ, nó đại diện cho một cái gì đó cụ thể trong thế giới vật lý thực. Nó thường có ý nghĩa để có nhiều tài liệu tham khảo cho cùng một điều. Ví dụ: địa chỉ nhà của tôi có thể được cung cấp cho nhiều người và tổ chức và địa chỉ đó luôn đề cập đến cùng một vị trí thực tế. Vì vậy, điểm đầu tiên là, các đối tượng thường đại diện cho một cái gì đó cụ thể, thực tế hoặc cụ thể; và vì vậy việc có thể có nhiều tài liệu tham khảo cho cùng một điều là vô cùng hữu ích. Nếu không sẽ khó hơn để viết chương trình.
Mỗi khi bạn chuyển a
làm đối số / tham số cho hàm khác, ví dụ như gọi
foo(Dog aDoggy);
hoặc áp dụng một phương thức a
, mã chương trình bên dưới sẽ tạo một bản sao của tham chiếu, để tạo tham chiếu thứ hai cho cùng một đối tượng.
Hơn nữa, nếu mã có tham chiếu được sao chép nằm trong một luồng khác nhau, thì cả hai có thể được sử dụng đồng thời để truy cập vào cùng một đối tượng.
Vì vậy, trong hầu hết các chương trình hữu ích, sẽ có nhiều tham chiếu đến cùng một đối tượng, bởi vì đó là ngữ nghĩa của hầu hết các ngôn ngữ lập trình OO.
Bây giờ, nếu chúng ta nghĩ về nó, bởi vì chuyển qua tham chiếu là cơ chế duy nhất có sẵn trong nhiều ngôn ngữ OO (C ++ hỗ trợ cả hai), chúng ta có thể mong đợi nó là hành vi mặc định 'đúng' .
IMHO, sử dụng tài liệu tham khảo là mặc định đúng , vì một vài lý do:
- Nó đảm bảo rằng giá trị của một đối tượng được sử dụng ở hai nơi khác nhau là như nhau. Hãy tưởng tượng việc đặt một đối tượng vào hai cấu trúc dữ liệu khác nhau (mảng, danh sách, v.v.) và thực hiện một số thao tác trên một đối tượng thay đổi nó. Đó có thể là một cơn ác mộng để gỡ lỗi. Quan trọng hơn, đó là cùng một đối tượng trong cả hai cấu trúc dữ liệu hoặc chương trình có lỗi.
- Bạn có thể vui vẻ cấu trúc lại mã thành một số hàm hoặc hợp nhất mã từ một số hàm thành một và ngữ nghĩa không thay đổi. Nếu ngôn ngữ không cung cấp ngữ nghĩa tham chiếu, việc sửa đổi mã sẽ còn phức tạp hơn nữa.
Ngoài ra còn có một đối số hiệu quả; tạo bản sao của toàn bộ các đối tượng là ít hiệu quả hơn so với sao chép một tài liệu tham khảo. Tuy nhiên, tôi nghĩ rằng bỏ lỡ điểm. Nhiều tham chiếu đến cùng một đối tượng có ý nghĩa hơn và dễ sử dụng hơn, vì chúng phù hợp với ngữ nghĩa của thế giới thực.
Vì vậy, IMHO, thường có ý nghĩa khi có nhiều tham chiếu đến cùng một đối tượng. Trong các trường hợp bất thường khi điều đó không có ý nghĩa trong ngữ cảnh của thuật toán, hầu hết các ngôn ngữ đều cung cấp khả năng tạo bản sao 'bản sao' hoặc bản sao sâu. Tuy nhiên đó không phải là mặc định.
Tôi nghĩ rằng những người tranh luận rằng điều này không nên là mặc định đang sử dụng ngôn ngữ không cung cấp bộ sưu tập rác tự động. Ví dụ, C ++ lỗi thời. Vấn đề ở đây là họ cần tìm cách thu thập các vật thể 'chết' và không đòi lại các vật thể vẫn có thể được yêu cầu; có nhiều tài liệu tham khảo cho cùng một đối tượng làm cho điều đó trở nên khó khăn.
Tôi nghĩ rằng, nếu C ++ có bộ sưu tập rác đủ chi phí thấp, để tất cả các đối tượng được tham chiếu là rác được thu thập, thì phần lớn sự phản đối sẽ biến mất. Vẫn sẽ có một số trường hợp trong đó ngữ nghĩa tham chiếu không phải là những gì cần thiết. Tuy nhiên, theo kinh nghiệm của tôi, những người có thể xác định những tình huống đó cũng thường có khả năng chọn ngữ nghĩa phù hợp.
Tôi tin rằng có một số bằng chứng cho thấy một lượng lớn mã trong chương trình C ++ có sẵn để xử lý hoặc giảm thiểu việc thu gom rác. Tuy nhiên, viết và duy trì loại mã 'cơ sở hạ tầng' đó làm tăng thêm chi phí; nó ở đó để làm cho ngôn ngữ dễ sử dụng hơn hoặc mạnh mẽ hơn. Vì vậy, ví dụ, ngôn ngữ Go được thiết kế tập trung vào việc khắc phục một số điểm yếu của C ++ và nó không có lựa chọn nào khác ngoài bộ sưu tập rác.
Điều này tất nhiên không liên quan trong bối cảnh của Java. Nó cũng được thiết kế để dễ sử dụng và bộ sưu tập rác cũng vậy. Do đó, có nhiều tài liệu tham khảo là ngữ nghĩa mặc định và tương đối an toàn theo nghĩa các đối tượng không được thu hồi trong khi có một tài liệu tham khảo cho chúng. Tất nhiên chúng có thể được giữ bởi một cấu trúc dữ liệu vì chương trình không được dọn dẹp đúng cách khi nó thực sự kết thúc với một đối tượng.
Vì vậy, xoay quanh câu hỏi của bạn (với một chút khái quát), khi nào bạn muốn có nhiều hơn một tham chiếu đến cùng một đối tượng? Khá nhiều trong mọi tình huống tôi có thể nghĩ ra. Chúng là ngữ nghĩa mặc định của hầu hết các cơ chế truyền tham số ngôn ngữ. Tôi đề nghị đó là bởi vì ngữ nghĩa mặc định của việc xử lý các đối tượng tồn tại trong thế giới thực khá nhiều phải được tham chiếu ('vì các đối tượng thực tế ở ngoài đó).
Bất kỳ ngữ nghĩa khác sẽ khó xử lý hơn.
Dog a = new Dog("rover"); // initialise with name
DogList dl = new DogList()
dl.add(a)
...
a.setOwner("Mr Been")
Tôi đề nghị rằng "rover" trong dl
nên được thực hiện bởi setOwner
hoặc các chương trình khó viết, hiểu, gỡ lỗi hoặc sửa đổi. Tôi nghĩ rằng hầu hết các lập trình viên sẽ bối rối hoặc mất tinh thần nếu không.
Sau đó, con chó được bán:
soldDog = dl.lookupOwner("rover", "Mr Been")
soldDog.setOwner("Mr Mcgoo")
Loại xử lý này là phổ biến và bình thường. Vì vậy, ngữ nghĩa tham chiếu là mặc định bởi vì nó thường có ý nghĩa nhất.
Tóm tắt: Luôn có ý nghĩa khi có nhiều tham chiếu đến cùng một đối tượng.