2010-06-25 26 views
10

Thông thường JavaPractices.com là một trang web tốt với ý tưởng hay, nhưng điều này làm tôi phiền lòng: JavaBeans are bad.Java Bean có phải là lớp lưu trữ dữ liệu thiết kế xấu không?

Bài viết trích dẫn một số lý do, chủ yếu là thuật ngữ JavaBean có nghĩa là "Hạt Java là một thành phần phần mềm có thể tái sử dụng có thể được xử lý trực quan trong công cụ xây dựng". không lưu trữ dữ liệu, vi phạm một số patters nhất định và phức tạp hơn.

Bây giờ tôi có thể đồng ý với điều cuối cùng, nhưng trong mắt tôi, JavaBeans trong danh sách có ý nghĩa hơn nhiều so với Bản đồ lồng nhau. Bài viết này cho rằng các khung công tác lập bản đồ cơ sở dữ liệu nên gọi các hàm tạo, không đặt các phương thức * và đối tượng sẽ không thay đổi. Tuy nhiên, trong tâm trí của tôi, gọi phương thức set * khi cố gắng xây dựng một đối tượng dễ đọc hơn new MappedObject("column1", "column2", "yet another column", "this is stupid");

Tôi cũng sử dụng lớp kiểu JavaBean cho những thứ khác ngoài lập bản đồ cơ sở dữ liệu, ví dụ như bot IRC. được cập nhật với nhiều thứ khác nhau. Tôi không muốn tạo một đối tượng mới mỗi khi có thông tin mới, tôi muốn thêm nó vào một cái hiện có.

Vì vậy, câu hỏi của tôi: Việc sử dụng JavaBeans để lưu trữ dữ liệu có thực hành không tốt và nên tránh hoặc hoàn toàn an toàn không?

+10

JavaBeans không đại diện cho mô hình như một ngôn ngữ chống mẫu toàn bộ. –

+3

bạn có thể sử dụng một người xây dựng để đạt được những lợi ích của bất biến và tránh các nhà xây dựng siêu dài. –

+6

Xem xét việc tìm hiểu về Mẫu Builder. http://en.wikipedia.org/wiki/Builder_pattern. – CoolBeans

Trả lời

19

Dường như bạn đang hiểu sai văn bản.

Bây giờ tôi có thể đồng ý với người cuối cùng, nhưng trong JavaBeans mắt tôi trong một danh sách có ý nghĩa rất nhiều hơn Maps lồng nhau

Các văn bản không bao giờ đề cập đến bản đồ lồng nhau như một sự thay thế (yiack)

... nên gọi nhà thầu, không được thiết lập * phương pháp, và đối tượng nên không thể thay đổi

Đây là một thực hành tốt, đặc biệt hữu ích khi xử lý các chuỗi.

Nhưng chúng tôi không thể nói rằng sử dụng các bộ định vị là baaad một trong hai, đặc biệt khi một sợi đơn đang sử dụng đối tượng. Điều đó hoàn toàn an toàn.

Tôi không muốn tạo đối tượng mới mỗi khi có thông tin mới, tôi muốn thêm nó vào một thông tin hiện có.

Tốt thôi, miễn là bạn kiểm soát đối tượng không có vấn đề gì với điều này, một số khác có thể dễ dàng hơn khi tạo đối tượng mới.

Bạn đang sử dụng JavaBeans để lưu trữ dữ liệu không tốt và nên tránh hoặc hoàn toàn an toàn?

Không, không phải là hành vi không tốt. Không phải là hoàn toàn an toàn. Tùy theo hoàn cảnh.

Sự cố với các đối tượng có thể thay đổi (không phải với JavaBeans per se) đang sử dụng các chuỗi khác nhau để truy cập chúng.

Bạn phải đồng bộ hóa quyền truy cập để tránh một chủ đề sửa đổi đối tượng trong khi người khác đang truy cập đối tượng đó.

Đối tượng không thể thay đổi không có vấn đề này, bởi vì, .. họ không thể thay đổi, và do đó, bạn không phải đồng bộ hóa bất kỳ thứ gì.

Để đảm bảo đối tượng không thay đổi, bạn phải khai báo thuộc tính của mình là cuối cùng.

class MyBean { 
    private final int i; 
} 

Nếu bạn muốn gán một giá trị hợp lý để MyBean.i bạn phải xác định nó trong constructor:

public MyBean(int i) { 
    this.i = i; 
} 

Kể từ khi biến là cuối cùng, bạn không thể sử dụng một setter. Bạn chỉ có thể cung cấp một getter.

Điều này hoàn toàn an toàn cho luồng và tốt nhất là bạn không phải đồng bộ hóa quyền truy cập, bởi vì nếu hai chủ đề cố gắng lấy giá trị i cả hai đều sẽ luôn thấy giá trị được gán trên instantiation, bạn không phải đồng bộ hóa bất cứ điều gì.

Hành nghề không tốt hoặc thực hành tốt.Phải của chúng tôi phải làm việc với một chủ đề duy nhất, ngay cả trong môi trường đa luồng như servlet.

Nếu trong tương lai bạn phải đối phó với các ứng dụng đa luồng, bạn có thể xem xét sử dụng một JavaBean bất biến;)

BTW, giải pháp thay thế để tạo ra đậu bất biến, và vẫn cung cấp một loạt các setters đang sử dụng Builders như :

Employee e = new EmployeeBuilder() 
        .setName("Oscar") 
        .setLastName("Reyes") 
        .setAge(0x1F) 
        .setEmployeeId("123forme") 
        .build(); 

Có vẻ khá giống với setXyz thông thường được sử dụng trong hạt thông thường với lợi ích của việc sử dụng dữ liệu không thay đổi.

Nếu bạn cần thay đổi một giá trị, bạn có thể sử dụng một phương pháp học:

Employee e = Employee.withName(e, "Mr. Oscar"); 

nào có đối tượng đang tồn tại, và sao chép tất cả các giá trị, và thiết lập một cái mới ....

public static EmployeeWithName(Employee e , String newName){ 
     return new Employee(newName, e.lastName, e.age, e.employeeId); 
    } 

Nhưng một lần nữa, trong một mô hình chuỗi đơn lẻ là hoàn toàn an toàn để sử dụng getters/setters.

PS Tôi thực sự khuyên bạn nên mua cuốn sách này: Effective Java. Bạn sẽ không bao giờ hối tiếc về nó, và bạn sẽ có thông tin để đánh giá các bài viết tốt hơn như một trích dẫn.

+0

+1 để có nội dung hay. Tôi đã nói về các bản đồ lồng nhau vì tôi sử dụng các bean cho những thứ khác ngoài các hàng cơ sở dữ liệu, các đối tượng người dùng phát triển IE. Tuy nhiên vì cả hai đều đang phát triển, tôi không chắc chắn con đường bất biến, mặc dù nó có lợi ích, tốt nhất ở đây vì nếu tôi muốn thay đổi đối tượng, tôi vẫn gặp sự cố đồng bộ + cố gắng thay thế đối tượng hiện có. – TheLQ

+0

@ Lord.Quackstar Có, nhưng hầu hết các lần thread đơn là đủ tốt, và Java đậu không phải là một mô hình xấu hay bất cứ điều gì. Họ chỉ là một thay thế. – OscarRyz

+0

Một điều bạn cũng có thể xem xét là có phương thức toBuilder cho bất kỳ bean nào, vì vậy bạn có thể biến bất kỳ bean nào thành một trình tạo, thiết lập một số trường và sau đó xây dựng lại đối tượng làm đối tượng mới. Vì vậy, bạn có thể làm employee = employee.toBuilder(). SetName ("Mary Poppins"). Build(); và điều đó sẽ cung cấp cho bạn một số bán-mutability. –

0

Nó hoàn toàn an toàn và thích hợp hơn nhiều so với không giới hạn lồng nhau java.util.Map. Bạn đạt được an toàn loại, dễ hiểu mã hơn và tránh mã của bạn kết thúc vào The Daily WTF. Lưu ý rằng việc triển khai cần được tách biệt - đừng trộn quá nhiều logic (ngoài xác thực đơn giản) vào các lớp lưu trữ dữ liệu của bạn. Bạn nên đọc về POJOs

3

"Mẫu JavaBeans có những bất lợi nghiêm trọng". — Joshua Bloch, Hiệu quả Java

Tôi yêu những người đó. Nhận báo giá tùy ý trong bối cảnh đã là lý do khiến tôi không tin vào bài viết đó.

BTW, sách được giới thiệu (Java hiệu dụng) có thảo luận sâu rộng về cả hai mô hình đó, ưu điểm, nhược điểm và lựa chọn thay thế của chúng. Bạn có thể muốn kiểm tra xem nó ra. Nhưng không có gì sai với JavaBeans, chỉ đôi khi chúng không phải là lựa chọn tốt nhất.

Edit: Xem mục 2 ("Hãy xem xét một người thợ xây khi phải đối mặt với nhiều thông số nhà xây dựng") trong Java hiệu quả trên Google Sách: http://books.google.com/books?id=ka2VUBqHiWkC&lpg=PP1&pg=PA11#v=onepage&q&f=false

+0

Tôi đồng ý rằng các đối số trong bài viết rất yếu, dựa trên các trích dẫn được đưa ra khỏi ngữ cảnh và bài viết không đề xuất một giải pháp thay thế rõ ràng hơn. Nói cách khác, @ Lord.Quackstar: không tin bất cứ điều gì bạn đọc trong một bài báo ngẫu nhiên trên Internet theo mệnh giá. – Jesper

0

ý Các bài viết của đều được nghĩa, nhưng trong đậu thực hành tránh và những người định cư là khó để duy trì. Ví dụ, việc sử dụng các khung công tác xây dựng là không thể trong nhiều trường hợp vì tên thường là tính năng nhận dạng và các tên tham số phương thức/constructor không được duy trì trong tệp .class. (Mặc dù có ít nhất một số library để giải quyết vấn đề này.)

Giải quyết là điều tốt nhất tiếp theo - không phải là OO "tinh khiết", nhưng thuận tiện hơn các nhà xây dựng và hoạt động tốt trong thực tế.

Kiểm tra thử nghiệm bắt đầu thất bại vì các hạt java "xấu", sau đó tôi sẽ xem xét lại nguyên nhân gây lo ngại. Nhưng tôi đã không thấy điều đó cho đến nay. Thời gian duy nhất tôi muốn nói rằng họ có lẽ không thích hợp là có đậu được chia sẻ trong mã đa luồng, kể từ khi đồng bộ hóa trạng thái có thể thay đổi được chia sẻ là khó khăn. Chỉ đạo rõ ràng rằng và đậu là tốt.

+0

Bạn sẽ nghĩ gì về "đậu java xấu"? – TheLQ

+0

"xấu" là sự hài hước của tôi tiêu đề bài viết - Tôi không nghĩ rằng họ là bản chất xấu - nhưng giống như tất cả các mẫu họ có thể bị lạm dụng để trở thành một anti-pattern. Có thể trong một số trường hợp, đậu có thể tạo ra sự tách rời không cần thiết giữa hành vi và dữ liệu, hoặc nơi mà dòng đơn getter/setter quen thuộc sẽ được thực hiện tốt hơn như một tính toán phong phú hơn. Và nếu chỉ các thuộc tính là khái niệm lớp đầu tiên thì chúng ta có thể xây dựng dựa trên mẫu mà không cần chuỗi (tên thuộc tính) và phản chiếu ... – mdma

+0

"Giữa instantiating lớp và thiết lập thuộc tính cuối cùng bạn có một đối tượng nằm trong nội bộ trạng thái không phù hợp hoặc không sử dụng được, "http://stackoverflow.com/a/3122912/262852 đó là vấn đề tóm lại. – Thufir

2

Lý do chính để tránh người định cư là bất biến. Mã cho bất biến lên phía trước và bạn tránh bất kỳ vấn đề luồng nào xung quanh các đối tượng đó.

Nếu bạn kết thúc với một constructor mà đọc

Người mới ("param 1", "param 2", "param 3", "param 4", "param 5", "param 6", "param 7", "param 8")

thì đối tượng của bạn quá phức tạp. Bạn sẽ cần các đối tượng Parameter (Xem cuốn sách Refactoring Martin Fowler).

Mã phòng thủ lúc bắt đầu và những người đi cùng và duy trì mã của bạn sẽ cảm ơn bạn (tốt) hoặc nguyền rủa bạn (vì họ không thể lười biếng và chỉ biến đổi đối tượng).

Khi bạn cần thay đổi đối tượng, hãy thêm hàm tạo bản sao (tức là phương pháp sao chép). Các JVM hiện đại đối phó với điều này một cách dễ dàng và nhanh chóng đủ và có rất ít hình phạt tốc độ. Bạn cũng làm mọi việc dễ dàng cho Hotspot và GC.

5

Phản đối của tôi khi sử dụng JavaBeans làm lớp lưu trữ dữ liệu là chúng cho phép đối tượng có trạng thái không nhất quán. Trong trường hợp sử dụng điển hình cho các loại đậu như vậy, bạn có các bước sau:

  • khởi tạo lớp;
  • đặt thuộc tính đầu tiên;
  • đặt thuộc tính thứ hai;
  • ...
  • đặt thuộc tính cuối cùng;
  • sử dụng cá thể đối tượng.

Bây giờ lớp học của bạn đã sẵn sàng để sử dụng. Vậy vấn đề ở đây là gì? Giữa việc khởi tạo lớp và thiết lập thuộc tính cuối cùng bạn có một đối tượng ở trạng thái không nhất quán hoặc không sử dụng được, nhưng không có gì ngăn cản bạn vô tình sử dụng nó.Tôi thích một hệ thống trong đó lớp được tự động ở trạng thái nhất quán, có thể sử dụng khi khởi tạo. Vì lý do này, tôi thích hoặc vượt qua tất cả trạng thái ban đầu trong hàm khởi tạo hoặc, nếu trạng thái ban đầu nói là quá phức tạp, hãy vượt qua trạng thái ban đầu dưới dạng bản đồ băm hoặc tập hợp hoặc tương tự. Trường hợp sử dụng hiện tại là:

  • (Tùy chọn: thiết lập đối tượng tham số);
  • khởi tạo lớp học;
  • sử dụng cá thể đối tượng.

Tại thời điểm này, tôi không thể bắt đầu sử dụng đối tượng có trạng thái không nhất quán. Nếu tôi sử dụng một đối tượng tham số, nó không được sử dụng trực tiếp cho bất kỳ thứ gì và nội dung của nó sẽ được xem xét khi khởi tạo lớp chính của tôi. Bản thân lớp chính, khi trở về từ instantiation, sẽ cho tôi một instance object được sử dụng ngay lập tức.

Kiểu thiết lập này là tốt nhất cho các đối tượng đơn giản, tất nhiên. Đối với các đối tượng phức tạp hơn với những thứ như thuộc tính tùy chọn, vv bạn sẽ muốn đi một bước xa hơn và sử dụng một cái gì đó giống như mô hình Builder mà những người khác đã chỉ cho bạn hướng tới. Nhà xây dựng là tốt đẹp khi bạn có kịch bản phức tạp hơn, IMO, nhưng để đơn giản hơn, parametrization đơn giản hơn chỉ bằng cách sử dụng đối số constructor hoặc một đối tượng tham số của một số loại là quá đủ.

Các vấn đề liên quan