JavaRush /Blog Java /Random-VI /Getters/Setters. Độc ác. Và thời kỳ
angelina
Mức độ

Getters/Setters. Độc ác. Và thời kỳ

Xuất bản trong nhóm
Bài viết của Egor Bugaenko ngày 19 tháng 9 năm 2014 | Đăng trong: Core Java Getters/Setters.  Độc ác.  Và điểm - 1 Cuộc tranh luận cũ này đã được bắt đầu bởi Allen Holub trong bài viết nổi tiếng của ông vào năm 2003, Tại sao các phương thức getter và setter lại xấu - getters/setters là một mô hình phản đối và chúng ta nên tránh chúng hay đó là thứ chúng ta phải làm nhất định phải có những điều cần thiết trong lập trình hướng đối tượng. Tôi sẽ thêm hai xu của mình vào cuộc thảo luận này. Ý chính của văn bản bên dưới là: getters và setters là những cách làm tồi; những người sử dụng chúng không có lý do gì. Nhưng một lần nữa, để tránh hiểu lầm, tôi hoàn toàn không gợi ý rằng nên tránh sử dụng get/set bất cứ khi nào có thể. KHÔNG. Tôi đang nói rằng bạn thậm chí còn không để họ đến gần mã của bạn . Getters/Setters.  Độc ác.  Và điểm - 2Bạn nghĩ gì về tuyên bố này? Đáng để bạn chú ý? Bạn đã sử dụng mẫu get/set được 15 năm và bạn có phải là kiến ​​trúc sư Java được kính trọng không? Và bạn thậm chí không muốn nghe những điều vô nghĩa này từ một người lạ? À... tôi hiểu cảm giác của bạn. Tôi cũng cảm thấy như vậy cho đến khi tình cờ đọc được cuốn sách “Tư duy đối tượng” của David West - đó là cuốn sách hay nhất về lập trình hướng đối tượng mà tôi từng đọc. Vì vậy xin. Hãy bình tĩnh và cố gắng hiểu những gì tôi đang cố giải thích. Chủ đề gây tranh cãi Có một số lập luận chống lại "accessors" (tên gọi khác của getters và setters) trong thế giới hướng đối tượng. Và đó đều là những lập luận rất đúng đắn. Chúng ta hãy xem nhanh chúng. Hỏi, đừng nói : Allen Holub nói, "Đừng hỏi thông tin bạn cần để thực hiện công việc; hãy hỏi đơn vị có thông tin đó để thực hiện công việc đó cho bạn." Nguyên tắc đóng gói bị vi phạm : Một đối tượng có thể bị các đối tượng khác tách rời vì chúng có thể nhúng bất kỳ dữ liệu nào vào đối tượng, thông qua setters. Một đối tượng đơn giản là không thể gói gọn trạng thái của chính nó đủ an toàn vì bất kỳ ai cũng có thể thay đổi trạng thái đó. Tiết lộ chi tiết triển khai : Nếu bạn có thể lấy một đối tượng từ một đối tượng khác thì chúng ta đang phụ thuộc quá nhiều vào chi tiết triển khai của đối tượng đầu tiên. Nếu ngày mai nó thay đổi (ví dụ như loại kết quả) thì chúng ta sẽ phải thay đổi mã. Tất cả những lời biện minh trên chắc chắn có lý, nhưng điều này lại bỏ sót điểm quan trọng nhất. Quan niệm sai lầm cơ bản Hầu hết các lập trình viên tin rằng một đối tượng là một cấu trúc dữ liệu có các phương thức. Tôi trích dẫn bài viết của Bozhidar Bozhanov: Getters và Setters không xấu xa. Nhưng hầu hết các đối tượng mà getters và setters được tạo chỉ đơn giản chứa dữ liệu. Quan niệm sai lầm này là kết quả của một sự hiểu lầm rất lớn! Các đối tượng không "chỉ lưu trữ dữ liệu." Các đối tượng không phải là cấu trúc dữ liệu có các phương thức được đính kèm. Khái niệm "lưu trữ dữ liệu" này xuất phát từ các ngôn ngữ thủ tục và lập trình hướng đối tượng, đặc biệt là C và COBOL. Tôi sẽ nhắc lại một lần nữa: một đối tượng không chỉ là một tập hợp các phần tử dữ liệu và các hàm thao tác với chúng. Một đối tượng không phải là một đối tượng dữ liệu. Vậy thì sao? Ball and Dog Trong lập trình hướng đối tượng thực sự, các đối tượng là những sinh vật sống, giống như bạn và tôi. Chúng là những sinh vật sống, có tập tính, đặc tính và vòng đời riêng. Một sinh vật sống có thể có một setter? Bạn có thể gắn (“đặt”) một quả bóng cho một con chó không? Đừng nghĩ. Nhưng đó chính xác là những gì đoạn mã bên dưới thực hiện:
Dog dog = new Dog();
dog.setBall(new Ball());
Vậy bạn thích nó như thế nào? Bạn có thể lấy (“lấy”) quả bóng ra khỏi con chó không? Vâng, hãy giả sử bạn có thể. Trong trường hợp cô ấy ăn nó và bạn đã phẫu thuật cho cô ấy. Trong trường hợp này, vâng, bạn sẽ có thể lấy (“lấy”) quả bóng từ con chó. Đây chính xác là những gì tôi đang nói đến:
Dog dog = new Dog();
Ball ball = dog.getBall();
Hoặc một ví dụ thậm chí còn nực cười hơn:
Dog dog = new Dog();
dog.setWeight("23kg");
Bạn có thể tưởng tượng điều này trong cuộc sống thực? Có vẻ như bạn viết mỗi ngày? Nếu có thì bạn là một lập trình viên thủ tục. Chỉ thừa nhận nó. Đây là những gì David West nói ở trang 30 trong cuốn sách của ông: Bước đầu tiên để biến một nhà phát triển thủ tục thành công thành một nhà phát triển mục tiêu thành công là phẫu thuật thùy não. Bạn có cần phẫu thuật thùy não không? Tôi chắc chắn cần nó và tôi đã có được nó khi đọc cuốn sách “Tư duy khách thể” của West. Tư duy khách quan Hãy bắt đầu suy nghĩ như một đồ vật và bạn sẽ ngay lập tức đổi tên các phương pháp này. Đây là những gì bạn có thể nhận được:
Dog dog = new Dog();
dog.take(new Ball());
Ball ball = dog.give();
Bây giờ chúng ta coi con chó như một con vật thực sự, nó có thể lấy quả bóng từ tay chúng ta và có thể trả lại nếu chúng ta yêu cầu. Để đề phòng, tôi lưu ý rằng con chó không thể trả về NULL. Chó không biết NULL là gì! Suy nghĩ khách quan (suy nghĩ) ngay lập tức loại bỏ các tham chiếu NULL khỏi mã của bạn. Getters/Setters.  Độc ác.  Và điểm - 3
A Fish Called Wanda (1988) của Charles Crichton
Ngoài ra, tư duy khách quan sẽ dẫn đến tính bất biến của một đối tượng, chẳng hạn như “trọng lượng của con chó” trong ví dụ của chúng tôi. Bạn sẽ viết lại mã như thế này:
Dog dog = new Dog("23kg");
int weight = dog.weight();
Con chó là một sinh vật sống không thể thay đổi, nó sẽ không cho phép bất cứ ai bên ngoài thay đổi trọng lượng, kích thước hoặc tên của nó, v.v. Cô ấy có thể "cho biết" cân nặng hoặc tên của mình theo yêu cầu. Không có gì sai với các phương thức công khai hiển thị các truy vấn cho các thuộc tính "nội bộ" nhất định của một đối tượng. Nhưng những phương thức này không phải là "getters" và chúng sẽ không bao giờ nhận được tiền tố "get". Chúng tôi không "ra khỏi" con chó. Chúng tôi không biết tên cô ấy. Chúng tôi yêu cầu cô ấy cho chúng tôi biết tên của cô ấy. Bạn có thấy sự khác biệt? Chúng tôi thậm chí không nói về ngữ nghĩa ở đây. Chúng tôi phân biệt cách tiếp cận theo thủ tục để lập trình với cách tiếp cận hướng đối tượng. Trong lập trình thủ tục, chúng ta làm việc với dữ liệu, thao tác, lấy, thiết lập và xóa dữ liệu nếu cần. Chúng tôi chịu trách nhiệm và dữ liệu chỉ là một thành phần thụ động. Một con chó chẳng là gì đối với chúng ta - nó chỉ đơn giản là “chứa dữ liệu”. Cô ấy không có cuộc sống riêng của mình. Chúng ta có thể tự do lấy (lấy) mọi thứ chúng ta cần từ nó và đặt (đặt) bất kỳ dữ liệu nào vào đó. Đây là cách C, COBOL, Pascal và các ngôn ngữ thủ tục khác hoạt động (đã hoạt động). Và tình hình hoàn toàn trái ngược trong thế giới hướng đối tượng. Ở đây chúng ta coi các đồ vật như những sinh vật sống, có ngày sinh và thời điểm chết, có tính cách và thói quen riêng, nếu bạn muốn. Chúng ta có thể yêu cầu con chó cung cấp cho chúng ta một phần dữ liệu (ví dụ: trọng lượng của nó) và nó có thể trả lại thông tin đó cho chúng ta. Nhưng hãy luôn nhớ rằng con chó là thành phần tích cực. Cô ấy quyết định điều gì sẽ xảy ra sau khi yêu cầu. Và đó là lý do tại sao việc các phương thức của một đối tượng bắt đầu bằng set hoặc get là hoàn toàn sai. Và đây thậm chí không phải là vi phạm đóng gói như nhiều người nghĩ. Điều này nói lên thực tế là bạn đang suy nghĩ như một đối tượng hoặc bạn vẫn đang viết COBOL bằng cú pháp Java. Tái bút . Và vâng, bạn có thể hỏi: "Còn JavaBeans, JPA, JAXB và nhiều API Java khác phụ thuộc vào get/set thì sao?" Còn chức năng tích hợp trong Ruby giúp tạo trình truy cập dễ dàng hơn thì sao? Chà, tôi có thể nói gì với bạn... bạn không gặp may rồi. Việc duy trì trong thế giới nguyên thủy của COBOL thủ tục sẽ dễ dàng hơn nhiều so với việc hiểu và đón nhận thế giới tuyệt vời của các đối tượng thực. P.P.S. _ Tôi quên nói, vâng, việc chèn các phần phụ thuộc thông qua một setter cũng là một kiểu phản đối khủng khiếp. Nhưng nhiều hơn về điều đó trong bài viết tiếp theo! Bài báo gốc
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION