Tại sao các lớp dữ liệu được coi là một mùi mã?


18

Bài viết này tuyên bố rằng một lớp dữ liệu là một "mùi mã". Nguyên nhân:

Đó là một điều bình thường khi một lớp mới được tạo chỉ chứa một vài trường công khai (và thậm chí có thể là một số ít getters / setters). Nhưng sức mạnh thực sự của các đối tượng là chúng có thể chứa các loại hành vi hoặc hoạt động trên dữ liệu của chúng.

Tại sao nó chỉ sai khi một đối tượng chỉ chứa dữ liệu? Nếu trách nhiệm cốt lõi của lớp là đại diện cho dữ liệu, thì việc thêm các phương thức hoạt động trên dữ liệu có phá vỡ Nguyên tắc Trách nhiệm duy nhất không?


1
Điều này sẽ phụ thuộc mạnh mẽ vào các tính năng ngôn ngữ. Ví dụ, trong Python, không có sự phân biệt giữa "trường" và các trình truy cập của nó, trừ khi bạn không muốn viết Java bằng Python .
jscs

1
Tôi nghĩ rằng có một số lớp chỉ có dữ liệu không phải là mùi mã mỗi se, nhưng nếu hầu hết các lớp đều như vậy thì chúng ta đang nói về "tên miền thiếu máu"
antipotype

1
Tôi không thấy câu hỏi này trùng lặp như thế nào. Các câu hỏi khác là về việc sử dụng các lớp dữ liệu trong OO, trong khi câu hỏi này là về nhược điểm của các lớp dữ liệu - các chủ đề hoàn toàn khác nhau.
Milos Mrdovic

Bạn có thể muốn đọc câu trả lời này trên stackoverflow khác biệt hơn nhiều so với câu trả lời được bình chọn hàng đầu ở đây quy định sự thấp kém của mô hình miền phong phú và trình bày nó như một thực tế đã được chứng minh. stackoverflow.com/questions/23314330/
trộm

Câu trả lời:


30

Hoàn toàn không có gì sai khi có các đối tượng dữ liệu thuần túy. Tác giả của tác phẩm khá thẳng thắn không biết anh ấy đang nói về cái gì.

Suy nghĩ như vậy bắt nguồn từ một ý tưởng cũ, thất bại, rằng "OO thật" là cách tốt nhất để lập trình và "OO thật" là tất cả về "mô hình dữ liệu phong phú" nơi người ta trộn lẫn dữ liệu và chức năng.

Thực tế đã cho chúng ta thấy rằng thực tế điều ngược lại là đúng, đặc biệt là trong thế giới của các giải pháp đa luồng này. Các hàm thuần túy, kết hợp với các đối tượng dữ liệu bất biến, là một cách tốt hơn để mã hóa.


1
Chỉ muốn thêm rằng các đối tượng dữ liệu thuần túy có thể là vô giá để mô hình hóa các mối quan hệ, xác nhận, kiểm soát truy cập / thay đổi.
Adrian

2
Mặc dù thật tuyệt nếu các hàm thuần túy đó chỉ lấy một thể hiện của đối tượng dữ liệu bất biến làm đối số được triển khai như các phương thức trên đối tượng dữ liệu.
RemcoGerlich

7
Nếu hàm lấy một đối số của kiểu dữ liệu đó, thì nó đã được ghép với dữ liệu.
RemcoGerlich

4
Bỏ phiếu vì điều này là không chính xác, hoặc tốt nhất là một vấn đề quan điểm. Trong ngôn ngữ OO, thường có ý nghĩa khi có một đối tượng chứa cả dữ liệu (vẫn có thể là bất biến!) Và các phương thức hành động trên nó. Các hàm thuần túy và dữ liệu riêng biệt rất tuyệt vời trong các mô hình ngôn ngữ khác, nhưng nếu bạn đang thực hiện OO, hãy thực hiện OO đầy đủ.
Marnen Laibow-Koser

3
Thực tế đã cho chúng ta thấy rất nhiều điều. -1 cho ý kiến ​​giáo điều "tất cả những người khác đã thất bại". Ngoài ra, tác giả không nói rằng các đối tượng dữ liệu thuần túy là "sai", chỉ là chúng là "mùi mã" và đáng để đặt câu hỏi. Tôi chỉ tiếc rằng tôi có một downvote để cung cấp cho đất nước của tôi. :-)
user949300

7

Hoàn toàn không có gì sai khi có các đối tượng dữ liệu thuần túy. Tác giả có ý kiến ​​không được chia sẻ bởi các nhà phát triển phần mềm mà tôi biết.

Đặc biệt đối với ánh xạ cơ sở dữ liệu, bạn nói chung có các lớp thực thể chỉ chứa các trường được lưu trữ trong cơ sở dữ liệu và getters và setters. Wikipedia Hibernate (khung)

Ý tưởng lỗ của các hạt Java được sử dụng bởi rất nhiều công cụ / khung công tác dựa trên các lớp dữ liệu được gọi là các hạt chỉ chứa các trường và các getters và setters liên quan. Wikipdia JavaBeans

Fazit:
Nếu ai đó tuyên bố rằng một cái gì đó là 'xấu' hoặc 'một mùi mã', bạn nên luôn luôn tìm kiếm những lý do được đưa ra. Nếu lý do không thuyết phục bạn hãy hỏi người khác vì lý do tốt hơn hoặc ý kiến ​​khác. (Giống như bạn đã làm trong diễn đàn này)


Tác giả không nói rằng các đối tượng dữ liệu thuần túy là "sai". Họ nói rằng các đối tượng dữ liệu thuần túy là một "mùi mã", có nghĩa là bạn nên suy nghĩ kỹ về việc sử dụng chúng.
dùng949300

1
@ user949300, bạn có vẻ bối rối. Nếu tác giả gọi chúng là mùi mã, thì ông cho biết có thể có điều gì đó không ổn với chúng. Vì chúng được công nhận rộng rãi ngày nay là một thực tiễn rất tốt, rõ ràng chúng không phải là mùi mã. Do đó MrSmith42 là chính xác: hoàn toàn không có gì sai với họ.
David Arno

4

Một lý lẽ tốt tại sao bởi Martin Fowler:

"Nói-Đừng-Hỏi là một nguyên tắc giúp mọi người nhớ rằng hướng đối tượng là về việc kết hợp dữ liệu với các chức năng hoạt động trên dữ liệu đó. Chúng tôi nhắc nhở chúng tôi rằng thay vì yêu cầu một đối tượng cho dữ liệu và hành động trên dữ liệu đó, chúng tôi thay vào đó nên nói cho một đối tượng phải làm gì. Điều này khuyến khích di chuyển hành vi vào một đối tượng đi cùng với dữ liệu. "

https://martinfowler.com/bliki/TellDontAsk.html


1
Vấn đề ở đây là Fowler hạn chế một cách giả tạo "nói không hỏi" bằng cách thay đổi các chức năng từ hỏi phạm vi rộng hơn sang chỉ hỏi phạm vi đối tượng. Họ vẫn đang hỏi. "Nói không hỏi" trên thực tế có thể tiến thêm một bước bằng cách thực sự nói với các chức năng đó thông qua danh sách đối số của chúng. Và do đó, chúng tôi đến các đối tượng dữ liệu và các chức năng (dữ liệu thông minh) riêng biệt là triển khai thực sự của "nói không hỏi". Vì vậy, thay vì là một lập luận tốt cho tuyên bố rằng các lớp dữ liệu là một mùi mã, trên thực tế nó lại chứng minh điều ngược lại.
David Arno

2
@DavidArno Bạn đang quên về việc đóng gói và ẩn. Bạn bảo một đối tượng thực thi một phương thức thành viên và phương thức thành viên đi vào hộp đen của đối tượng và làm bất cứ điều gì nó có để có câu trả lời. Nếu bạn hỏi một đối tượng từ bên ngoài, bạn không có quyền truy cập vào trạng thái riêng tư của nó và do đó, đối tượng phơi bày nhiều trạng thái hơn là khôn ngoan, hoặc người hỏi phải nhảy qua nhiều vòng hơn mức cần thiết. Tôi không hiểu tại sao bạn từng yêu cầu một đối tượng trong môi trường OO. (Tất nhiên các mô hình lập trình khác có thể yêu cầu các cách tiếp cận khác nhau, tất nhiên.)
Marnen Laibow-Koser

2
@DavidArno Tất nhiên bạn có thể truyền bazvào dưới dạng tham số cho phương thức tĩnh, nhưng để làm điều đó, trước tiên bạn cần phải hỏi đối tượng cho nó. Có lẽ trong mô hình lập trình nơi các phương thức là chính (như giả sử, lập trình chức năng) điều này có ý nghĩa, nhưng trong môi trường OO, điều đó hoàn toàn không, bởi vì các đối tượng là chính và nên chứa cả dữ liệu và các hàm để hành động trên nó. Yêu cầu của bạn rằng việc loại bỏ phương thức khỏi đối tượng đã tăng đóng gói cũng chính xác là ngược , theo như tôi có thể nói, bởi vì điều đó có nghĩa là bây giờ bạn đã bazxuất hiện bên ngoài đối tượng.
Marnen Laibow-Koser

1
@ MarnenLaibow-Koser, tôi không yêu cầu "làm OO". Tôi viết mã và tôi sử dụng các kỹ thuật tốt để làm như vậy. Cho dù những kỹ thuật đó đến từ mô hình chức năng, hay mô hình OO, hay mô hình ai-cho-một-chết tiệt đều không quan tâm đến tôi. Chọn một mô hình và gắn bó với nó một cách đầy đủ nhất có thể là giáo điều thuần túy. Điều đó thật tồi tệ. Nó là vô lý. Nó kìm hãm bạn và dẫn đến mã kém hơn. Đừng làm điều đó.
David Arno

1
@DavidArno Ngược lại, nếu bạn cam kết hoàn toàn với một mô hình (bất kỳ mô hình tử tế nào, không chỉ OO), bạn sẽ có được sự trừu tượng hóa ở mức độ cao mạnh mẽ và mã duy trì một cách hợp lý. Tôi không nói điều này là giáo điều, mà là thực dụng. Tôi đã thấy và duy trì quá nhiều mã rõ ràng được tạo ra với thái độ như của bạn, nơi tác giả không thực sự cam kết về tính nhất quán logic của hệ thống được sử dụng. Thật khó hiểu, khó duy trì và khó sửa đổi. Không có mô hình nào là hoàn hảo, nhưng nhìn chung một hỗn hợp (trừ khi được xem xét cẩn thận) là khó hiểu hơn.
Marnen Laibow-Koser

2

Điều bạn cần hiểu là có hai loại đối tượng:

  • Đối tượng có hành vi . Những người này không được phép truy cập công khai vào hầu hết / bất kỳ thành viên dữ liệu nào của họ. Tôi hy vọng chỉ có rất ít phương thức truy cập được xác định cho những điều này.

    Một ví dụ sẽ là một regex được biên dịch: Đối tượng được tạo để cung cấp một hành vi nhất định (để khớp một chuỗi với một regex cụ thể và để báo cáo các phần khớp (một phần)), nhưng cách thức regex được biên dịch thực hiện không phải là của người dùng kinh doanh.

    Hầu hết các lớp học mà tôi viết là trong thể loại này.

  • Các đối tượng thực sự chỉ là dữ liệu . Chúng chỉ nên khai báo tất cả các thành viên của họ công khai (hoặc cung cấp đầy đủ bộ truy cập cho họ).

    Một ví dụ sẽ là một lớp học Point2D. Hoàn toàn không có bất kỳ sự bất biến nào cần được đảm bảo cho các thành viên của lớp này và người dùng sẽ có thể chỉ cần truy cập dữ liệu qua myPoint.xmyPoint.y.

    Cá nhân, tôi không sử dụng các lớp như vậy nhiều, nhưng tôi đoán không có đoạn mã nào lớn hơn mà tôi đã viết mà không sử dụng một lớp như vậy ở đâu đó.

Trở nên thành thạo với định hướng đối tượng bao gồm nhận ra rằng sự khác biệt này tồn tại và học cách phân loại chức năng của một lớp thành một trong hai loại này.


Nếu bạn viết mã trong C ++, bạn có thể phân biệt rõ ràng bằng cách sử dụng classcho loại đối tượng đầu tiên và structthứ hai. Tất nhiên, hai cái này tương đương nhau, ngoại trừ điều đó classcó nghĩa là tất cả các thành viên đều ở chế độ riêng tư theo mặc định, trong khi structtuyên bố tất cả các thành viên theo mặc định. Đó chính xác là loại thông tin bạn muốn truyền đạt.


1
Một lời giải thích cho downvote sẽ rất tuyệt ...
cmaster - phục hồi monica

Cảm ơn câu trả lời. Tôi ghét nó khi mọi người downvote không có lý do. Nếu bạn có một vấn đề với một câu trả lời, giải thích tại sao .
Sipo
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.