Bạn sẽ truy cập các thuộc tính Object từ bên trong một phương thức object như thế nào? [đóng cửa]


96

Cách "thuần túy" hoặc "chính xác" để truy cập thuộc tính của một đối tượng từ bên trong một phương thức đối tượng không phải là một phương thức getter / setter là gì?

Tôi biết rằng từ bên ngoài đối tượng, bạn nên sử dụng getter / setter, nhưng từ bên trong, bạn chỉ cần làm:

Java:

String property = this.property;

PHP:

$property = $this->property;

hoặc bạn sẽ làm:

Java:

String property = this.getProperty();

PHP:

$property = $this->getProperty();

Thứ lỗi cho tôi nếu Java của tôi hơi sai, đã một năm kể từ khi tôi lập trình bằng Java ...

BIÊN TẬP:

Có vẻ như mọi người đang cho rằng tôi chỉ đang nói về các biến / thuộc tính riêng tư hoặc được bảo vệ. Khi tôi học OO, tôi đã được dạy sử dụng getters / setters cho mọi thuộc tính ngay cả khi nó là công khai (và thực sự tôi đã được bảo là không bao giờ đặt bất kỳ biến / thuộc tính nào ở chế độ công khai). Vì vậy, tôi có thể bắt đầu từ một giả định sai lầm ngay từ đầu. Có vẻ như những người trả lời câu hỏi này có thể nói rằng bạn nên có tài sản công cộng và những tài sản đó không cần bộ định vị và bộ định vị, điều này đi ngược lại những gì tôi đã được dạy và những gì tôi đang nói, mặc dù có thể điều đó cần được thảo luận như tốt. Đó có lẽ là một chủ đề hay cho một câu hỏi khác ...

Câu trả lời:


62

Điều này có khả năng xảy ra chiến tranh tôn giáo, nhưng có vẻ như với tôi rằng nếu bạn đang sử dụng getter / setter, bạn cũng nên sử dụng nó trong nội bộ - sử dụng cả hai sẽ dẫn đến các vấn đề bảo trì trong quá trình thực hiện (ví dụ: ai đó thêm mã vào một setter cần để chạy mỗi khi thuộc tính đó được thiết lập và thuộc tính đang được đặt bên trong khi bộ thiết lập đó được gọi).


không làm bất cứ điều gì khác trong một trình cài đặt ngoài việc đặt giá trị của thuộc tính, ví dụ về việc sử dụng sai trong Java.
euphoria83

1
@ euphoria83 Có lẽ, nhưng điều đó không loại trừ nó xảy ra.
Greg Hurlman

Tôi đồng ý với câu trả lời ban đầu. Tuy nhiên, chỉ cần nhớ rằng nếu bạn đang thiết lập hoặc nhận một cái gì đó riêng tư bên trong lớp hoặc đối tượng, bạn cần đảm bảo getter / setter không theo chu kỳ hoặc dư thừa theo một cách nào đó khiến mã của bạn bị lỗi. Nếu bạn không thể sử dụng getter / setter, hãy truy cập trực tiếp vào nó. (Ví dụ: getter / setter của bạn truy cập một phương thức phụ (riêng tư / được bảo vệ) để thao tác dữ liệu.)
Rick Mac Gillis

43

Cá nhân tôi cảm thấy điều quan trọng là phải duy trì sự nhất quán. Nếu bạn có getters và setters, hãy sử dụng chúng. Lần duy nhất tôi có thể truy cập trực tiếp vào một trường là khi trình truy cập có nhiều chi phí. Bạn có thể cảm thấy như bạn đang làm đầy mã của mình một cách không cần thiết, nhưng nó chắc chắn có thể giúp bạn đỡ đau đầu hơn trong tương lai. Ví dụ cổ điển:

Sau này, bạn có thể muốn thay đổi cách trường đó hoạt động. Có thể nó nên được tính toán ngay lập tức hoặc có thể bạn muốn sử dụng một loại khác cho cửa hàng phụ trợ. Nếu bạn đang truy cập trực tiếp vào thuộc tính, một thay đổi như vậy có thể phá vỡ rất nhiều mã trong một lần mở rộng.


26

Tôi khá ngạc nhiên về mức độ nhất trí của tình cảm đó gettersvà những người sắp đặt vẫn ổn và tốt. Tôi đề nghị bài báo gây cháy nổ của Allen Holub "Người lập công và người định cư đều xấu xa ". Đúng là tiêu đề có giá trị gây sốc, nhưng tác giả đưa ra những điểm hợp lệ.

Về cơ bản, nếu bạn có getterssettersđối với mỗi và mọi lĩnh vực riêng tư, bạn đang làm cho những lĩnh vực đó tốt như công khai. Bạn sẽ rất khó thay đổi loại trường riêng tư mà không có hiệu ứng gợn sóng đối với mọi lớp gọi đó getter.

Hơn nữa, theo quan điểm OO hoàn toàn, các đối tượng nên phản hồi các thông báo (phương thức) tương ứng với trách nhiệm đơn lẻ (hy vọng) của chúng. Phần lớn getterssetterskhông có ý nghĩa đối với các đối tượng cấu thành của chúng; Pen.dispenseInkOnto(Surface)có ý nghĩa hơn đối với tôi Pen.getColor().

Getters và setters cũng khuyến khích người dùng của lớp yêu cầu đối tượng cung cấp một số dữ liệu, thực hiện một phép tính và sau đó đặt một số giá trị khác trong đối tượng, hay còn gọi là lập trình thủ tục. Tốt hơn hết bạn nên chỉ bảo đối tượng làm những gì bạn sẽ làm ngay từ đầu; còn được gọi là thành ngữ Chuyên gia thông tin .

Tuy nhiên, Getters và setters là những tệ nạn cần thiết ở ranh giới của các lớp - giao diện người dùng, sự bền bỉ, v.v. Quyền truy cập hạn chế vào nội bộ của một lớp, chẳng hạn như từ khóa bạn bè của C ++, quyền truy cập được bảo vệ bằng gói của Java, quyền truy cập nội bộ của .NET và Mẫu lớp bạn bè có thể giúp bạn giảm khả năng hiển thị gettersvà người thiết lập chỉ những người cần chúng.


19

Nó phụ thuộc vào cách tài sản được sử dụng. Ví dụ: giả sử bạn có một đối tượng student có thuộc tính name. Bạn có thể sử dụng phương thức Get để lấy tên từ cơ sở dữ liệu, nếu nó chưa được truy xuất. Bằng cách này, bạn đang giảm bớt các cuộc gọi không cần thiết đến cơ sở dữ liệu.

Bây giờ, giả sử bạn có một bộ đếm số nguyên riêng trong đối tượng của bạn để đếm số lần tên đã được gọi. Bạn có thể không muốn sử dụng phương thức Get từ bên trong đối tượng vì nó sẽ tạo ra một số lượng không hợp lệ.


Nếu đối tượng Sinh viên là đối tượng doanh nghiệp / miền, bạn hiện đang trộn các chi tiết cơ sở hạ tầng. Tốt nhất, một đối tượng doanh nghiệp / miền chỉ nên quan tâm đến logic kinh doanh / miền.
moffdub 19/09/08

Điều gì sẽ xảy ra nếu bạn thêm một số loại boolean vào getter như: PHP: public function getName ($ externalCall = true) {if ($ externalCall) {$ this-> incrementNameCalled (); } return $ this-> name; } và sau đó từ bên trong chính Đối tượng, nếu bạn gọi tên get, bạn có thể giữ cho nó không tăng lên bằng cách: PHP: $ name = $ this-> getName (false); Tôi chỉ đi quá đà ở đây?
cmcculloh

14

PHP cung cấp vô số cách để xử lý điều này, bao gồm cả các phương thức ma thuật __get__set, nhưng tôi thích trình duyệt và trình cài đặt rõ ràng hơn. Đây là lý do tại sao:

  1. Việc xác nhận có thể được đặt trong bộ định tuyến (và bộ xác nhận cho vấn đề đó)
  2. Intellisense hoạt động với các phương pháp rõ ràng
  3. Không có câu hỏi liệu một thuộc tính là chỉ đọc, chỉ ghi hay đọc-ghi
  4. Truy xuất các thuộc tính ảo (tức là các giá trị được tính toán) trông giống như các thuộc tính thông thường
  5. Bạn có thể dễ dàng đặt một thuộc tính đối tượng chưa bao giờ thực sự được xác định ở bất kỳ đâu, sau đó sẽ không có tài liệu

13

Tôi chỉ đi quá đà ở đây?

Có lẽ ;)

Một cách tiếp cận khác sẽ là sử dụng phương thức riêng tư / được bảo vệ để thực sự thực hiện việc nhận (bộ nhớ đệm / db / etc) và một trình bao bọc công khai cho nó để tăng số lượng:

PHP:

public function getName() {
    $this->incrementNameCalled();
    return $this->_getName();
}

protected function _getName() {
    return $this->name;
}

và sau đó từ bên trong chính đối tượng:

PHP:

$name = $this->_getName();

Bằng cách này, bạn vẫn có thể sử dụng đối số đầu tiên đó cho một thứ khác (chẳng hạn như gửi cờ cho biết có thể có hay không sử dụng dữ liệu được lưu trong bộ nhớ cache ở đây).


12

Tôi phải thiếu điểm ở đây, tại sao bạn lại sử dụng getter bên trong một đối tượng để truy cập thuộc tính của đối tượng đó?

Kết luận này là getter nên gọi getter, getter sẽ gọi là getter.

Vì vậy, tôi muốn nói rằng bên trong một phương thức đối tượng truy cập trực tiếp vào một thuộc tính, đặc biệt là việc gọi một phương thức khác trong đối tượng đó (sẽ chỉ truy cập trực tiếp vào thuộc tính sau đó trả về nó) chỉ là một bài tập vô nghĩa, lãng phí (hoặc tôi đã hiểu sai câu hỏi ).


Tôi được thúc đẩy bởi nhu cầu tương tự bạn phải bình luận ... Thêm vào đó nó đã được trả lời không khép kín;)
Trứng Vans

8

Cách OO thuần túy nhất là tránh cả hai và tuân theo Định luật Demeter bằng cách sử dụng phương pháp Tell Don't Ask .

Thay vì lấy giá trị thuộc tính của đối tượng, nó kết hợp chặt chẽ giữa hai lớp, hãy sử dụng đối tượng làm tham số, ví dụ:

  doSomethingWithProperty() {
     doSomethingWith( this.property ) ;
  }

Trong đó thuộc tính là một kiểu gốc, ví dụ int, sử dụng một phương thức truy cập, đặt tên cho miền sự cố không phải miền lập trình.

  doSomethingWithProperty( this.daysPerWeek() ) ;

Những điều này sẽ cho phép bạn duy trì đóng gói và bất kỳ điều kiện hậu kỳ hoặc bất biến phụ thuộc. Bạn cũng có thể sử dụng phương pháp setter để duy trì bất kỳ điều kiện trước hoặc bất biến phụ thuộc nào, tuy nhiên, đừng rơi vào bẫy đặt tên chúng là setter, hãy quay lại Nguyên tắc Hollywood để đặt tên khi sử dụng thành ngữ.


8

Tốt hơn là sử dụng các phương thức truy cập, ngay cả trong đối tượng. Đây là những điểm tôi nghĩ ngay đến:

  1. Nó nên được thực hiện vì lợi ích của việc duy trì tính nhất quán với các truy cập được thực hiện từ bên ngoài đối tượng.

  2. Trong một số trường hợp, các phương thức truy cập này có thể làm được nhiều việc hơn là chỉ truy cập trường; họ có thể đang thực hiện một số xử lý bổ sung (tuy nhiên điều này rất hiếm). Nếu đúng như vậy, việc truy cập trực tiếp vào trường có nghĩa là bạn đang thiếu quá trình xử lý bổ sung đó và chương trình của bạn có thể gặp trục trặc nếu quá trình xử lý này luôn được thực hiện trong các lần truy cập đó.


8

Nếu ý của bạn là "hầu hết đóng gói" bởi "purist", thì tôi thường khai báo tất cả các trường của mình là riêng tư và sau đó sử dụng "this.field" từ bên trong chính lớp đó. Đối với các lớp khác, bao gồm cả các lớp con, tôi truy cập trạng thái cá thể bằng cách sử dụng getters.


7

tôi thấy việc sử dụng setters / getters đã làm cho mã của tôi dễ đọc hơn. Tôi cũng thích sự kiểm soát mà nó cung cấp khi các lớp khác sử dụng các phương thức và nếu tôi thay đổi dữ liệu thuộc tính sẽ lưu trữ.


7

Các trường riêng tư có thuộc tính công khai hoặc được bảo vệ. Quyền truy cập vào các giá trị phải đi qua các thuộc tính và được sao chép vào một biến cục bộ nếu chúng được sử dụng nhiều lần trong một phương thức. Nếu và CHỈ nếu bạn có phần còn lại của ứng dụng của mình được tinh chỉnh hoàn toàn, thay đổi hoàn toàn và được tối ưu hóa đến mức mà việc truy cập các giá trị bằng cách đi qua các thuộc tính được liên kết của chúng đã trở thành một nút thắt cổ chai (Và điều đó sẽ không bao giờ xảy ra, tôi đảm bảo) nếu bạn bắt đầu để xem xét để bất kỳ thứ gì khác ngoài thuộc tính chạm trực tiếp vào các biến hỗ trợ của chúng.

Các nhà phát triển .NET có thể sử dụng các thuộc tính tự động để thực thi điều này vì bạn thậm chí không thể nhìn thấy các biến hỗ trợ tại thời điểm thiết kế.


7

Nó phụ thuộc. Đó là một vấn đề về phong cách hơn bất cứ điều gì khác và không có quy tắc cứng.


7

Tôi có thể sai vì tôi đang autodidact, nhưng tôi KHÔNG BAO GIỜ thuộc tính công khai của người dùng trong các lớp Java của tôi, chúng luôn là riêng tư hoặc được bảo vệ, do đó mã bên ngoài phải truy cập bởi getters / setters. Nó tốt hơn cho các mục đích bảo trì / sửa đổi. Và đối với mã lớp bên trong ... Nếu phương thức getter là nhỏ, tôi sử dụng thuộc tính trực tiếp, nhưng tôi luôn sử dụng các phương thức setter vì tôi có thể dễ dàng thêm mã vào các sự kiện kích hoạt nếu muốn.


7

Nếu tôi không chỉnh sửa thuộc tính, tôi sẽ sử dụng một phương thức công khai get_property()trừ khi đó là một dịp đặc biệt, chẳng hạn như một đối tượng MySQLi bên trong một đối tượng khác, trong trường hợp đó, tôi sẽ chỉ đặt thuộc tính công khai và gọi nó là$obj->object_property .

Bên trong đối tượng, nó luôn là thuộc tính $ this-> cho tôi.


5

Vâng, có vẻ như với việc triển khai mặc định của thuộc tính C # 3.0, quyết định được thực hiện cho bạn; bạn PHẢI đặt thuộc tính bằng cách sử dụng bộ thiết lập thuộc tính (có thể là riêng tư).

Cá nhân tôi chỉ sử dụng private member-Behind khi không làm như vậy sẽ khiến đối tượng rơi vào trạng thái ít hơn mong muốn, chẳng hạn như khi khởi tạo hoặc khi liên quan đến bộ nhớ đệm / tải chậm.


5

Tôi thích câu trả lời của cmcculloh , nhưng có vẻ như câu đúng nhất là câu trả lời của Greg Hurlman . Sử dụng getter / setter mọi lúc nếu bạn bắt đầu sử dụng chúng ngay từ đầu và / hoặc bạn đã quen làm việc với chúng.

Ngoài ra, cá nhân tôi thấy rằng việc sử dụng getter / setter làm cho mã dễ đọc hơn và gỡ lỗi sau này.


4

Như đã nêu trong một số nhận xét: Đôi khi bạn nên, đôi khi bạn không nên. Phần tuyệt vời của biến riêng là bạn có thể thấy tất cả những nơi chúng được sử dụng khi bạn thay đổi thứ gì đó. Nếu getter / setter của bạn làm điều gì đó bạn cần, hãy sử dụng nó. Nếu nó không quan trọng bạn quyết định.

Có thể xảy ra trường hợp ngược lại là nếu bạn sử dụng getter / setter và ai đó thay đổi getter / setter thì họ phải phân tích tất cả những nơi mà getter và setter được sử dụng trong nội bộ để xem liệu nó có làm rối tung điều gì không.

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.