Bạn không thể viết mã tốt mà không có getters.
Lý do tại sao không phải vì getters không phá vỡ đóng gói, họ làm. Không phải vì getters không cám dỗ mọi người không bận tâm theo OOP mà họ sẽ đưa phương thức vào dữ liệu họ hành động. Họ làm. Không, bạn cần getters vì ranh giới.
Các ý tưởng đóng gói và giữ các phương thức cùng với dữ liệu mà chúng hành động chỉ đơn giản là không hoạt động khi bạn chạy vào một ranh giới ngăn bạn di chuyển một phương thức và do đó buộc bạn phải di chuyển dữ liệu.
Nó thực sự đơn giản. Nếu bạn sử dụng getters khi không có ranh giới, cuối cùng bạn không có đối tượng thực sự. Mọi thứ bắt đầu có xu hướng thủ tục. Mà hoạt động tốt như nó từng làm.
OOP thực sự không phải là thứ bạn có thể lan truyền khắp nơi. Nó chỉ hoạt động trong những ranh giới đó.
Những ranh giới đó không mỏng như dao cạo. Họ có mã trong đó. Mã đó không thể là OOP. Nó cũng không thể hoạt động được. Không có mã này có lý tưởng của chúng tôi bị tước khỏi nó để nó có thể đối phó với thực tế khắc nghiệt.
Michael Fetters gọi mã này là fascia sau mô liên kết màu trắng đó giữ các phần của một quả cam lại với nhau.
Đây là một cách tuyệt vời để suy nghĩ về nó. Nó giải thích tại sao bạn có thể có cả hai loại mã trong cùng một cơ sở mã. Không có viễn cảnh này, nhiều lập trình viên mới bám chặt vào lý tưởng của họ, rồi trái tim họ tan vỡ và từ bỏ những lý tưởng này khi họ chạm đến ranh giới đầu tiên.
Các lý tưởng chỉ làm việc ở vị trí thích hợp của họ. Đừng từ bỏ chúng chỉ vì chúng không hoạt động ở mọi nơi. Sử dụng chúng ở nơi họ làm việc. Nơi đó là phần ngon ngọt mà fascia bảo vệ.
Một ví dụ đơn giản về một ranh giới là một bộ sưu tập. Cái này giữ một cái gì đó và không biết nó là gì. Làm thế nào một nhà thiết kế bộ sưu tập có thể chuyển chức năng hành vi của đối tượng bị giữ vào bộ sưu tập khi họ không biết nó sẽ được giữ gì? Bạn không thể. Bạn đang chống lại một ranh giới. Đó là lý do tại sao các bộ sưu tập có getters.
Bây giờ nếu bạn đã biết, bạn có thể di chuyển hành vi đó và tránh chuyển trạng thái. Khi bạn biết, bạn nên. Bạn không phải lúc nào cũng biết.
Một số người chỉ gọi điều này là thực dụng. Và nó là. Nhưng thật tuyệt khi biết tại sao chúng ta phải thực dụng.
Bạn đã bày tỏ rằng bạn không muốn nghe những tranh luận ngữ nghĩa và dường như đang ủng hộ việc đưa "những người thu hút hợp lý" đi khắp mọi nơi. Bạn đang yêu cầu ý tưởng này được thử thách. Tôi nghĩ rằng tôi có thể cho thấy ý tưởng có vấn đề với cách bạn đóng khung nó. Nhưng nó cũng nghĩ tôi biết bạn đến từ đâu vì tôi đã ở đó.
Nếu bạn muốn getters ở khắp mọi nơi hãy nhìn vào Python. Không có từ khóa riêng. Tuy nhiên Python vẫn OOP tốt. Làm sao? Họ sử dụng một mánh khóe ngữ nghĩa. Họ đặt tên cho bất cứ điều gì có nghĩa là riêng tư với một dấu gạch dưới hàng đầu. Bạn thậm chí được phép đọc từ nó với điều kiện bạn phải chịu trách nhiệm cho việc đó. "Chúng ta đều là người lớn ở đây", họ thường nói.
Vì vậy, sự khác biệt giữa điều đó và chỉ đưa getters vào mọi thứ trong Java hoặc C #? Xin lỗi nhưng đó là ngữ nghĩa. Hội nghị gạch dưới của Pythons báo hiệu rõ ràng cho bạn rằng bạn đang chọc vào đằng sau cánh cửa chỉ của nhân viên. Tát getters trên tất cả mọi thứ và bạn mất tín hiệu đó. Với sự phản chiếu, dù sao bạn cũng có thể loại bỏ sự riêng tư và vẫn không bị mất tín hiệu ngữ nghĩa. Đơn giản là không có một lập luận cấu trúc nào được đưa ra ở đây.
Vì vậy, những gì chúng tôi còn lại là công việc quyết định nơi treo biển hiệu "chỉ nhân viên". Những gì nên được coi là riêng tư? Bạn gọi đó là "getters hợp lý". Như tôi đã nói, sự biện minh tốt nhất cho một người đi bộ là một ranh giới buộc chúng ta tránh xa lý tưởng của mình. Điều đó không nên dẫn đến getters trên tất cả mọi thứ. Khi nó không dẫn đến một getter, bạn nên xem xét chuyển hành vi hơn nữa vào bit juicy nơi bạn có thể bảo vệ nó.
Sự tách biệt này đã dẫn đến một vài điều khoản. Đối tượng truyền dữ liệu hoặc DTO, không có hành vi. Các phương thức duy nhất là getters và đôi khi setters, đôi khi là một constructor. Tên này thật đáng tiếc vì nó hoàn toàn không phải là một đối tượng. Các getters và setters thực sự chỉ là mã gỡ lỗi cung cấp cho bạn một nơi để thiết lập một điểm dừng. Nếu không có nhu cầu đó, họ sẽ chỉ là một đống các lĩnh vực công cộng. Trong C ++, chúng tôi thường gọi chúng là structs. Sự khác biệt duy nhất họ có từ một lớp C ++ là họ được mặc định công khai.
DTO rất tuyệt vì bạn có thể ném chúng qua một bức tường ranh giới và giữ các phương thức khác của bạn an toàn trong một đối tượng hành vi ngon ngọt. Một đối tượng thực sự. Không có getters để vi phạm đóng gói của nó. Các đối tượng hành vi của tôi có thể ăn DTO bằng cách sử dụng chúng làm Đối tượng tham số . Đôi khi tôi phải tạo một bản sao phòng thủ của nó để ngăn chặn trạng thái đột biến được chia sẻ . Tôi không lan truyền các DTO đột biến xung quanh bên trong phần ngon ngọt trong ranh giới. Tôi gói gọn chúng. Tôi giấu chúng. Và cuối cùng khi tôi chạy vào một ranh giới mới, tôi quay lên một DTO mới và ném nó lên tường, do đó biến nó thành vấn đề của người khác.
Nhưng bạn muốn cung cấp getters thể hiện bản sắc. Xin chúc mừng bạn đã tìm thấy một biên giới. Các thực thể có một bản sắc vượt ra ngoài tham chiếu của họ. Đó là, ngoài địa chỉ bộ nhớ của họ. Vì vậy, nó phải được lưu trữ ở đâu đó. Và một cái gì đó phải có thể đề cập đến điều này bằng bản sắc của nó. Một getter thể hiện bản sắc là hoàn toàn hợp lý. Một đống mã sử dụng getter đó để đưa ra quyết định mà Thực thể có thể tự đưa ra là không.
Cuối cùng, đó không phải là sự tồn tại của getters mà là sai. Họ là tốt hơn nhiều so với các lĩnh vực công cộng. Điều tồi tệ là khi chúng được sử dụng để giả vờ rằng bạn đang hướng đối tượng khi bạn không. Getters là tốt. Được hướng đối tượng là tốt. Getters không phải là hướng đối tượng. Sử dụng getters để khắc ra một nơi an toàn để được hướng đối tượng.