2009-05-26 10 views
18

Tôi chỉ bắt đầu với Hibernate, và tất cả các ví dụ tôi nhìn thấy cho đến nay trông khá giống như những hướng dẫn trong tài liệu Hibernate:Có cách nào để khai báo các trường cuối cùng cho các đối tượng được quản lý Hibernate không?

package org.hibernate.tutorial.domain; 
import java.util.Date; 

public class Event { 

    private Long id; 
    private String title; 
    private Date date; 

    public Event() {} 

    /* Accessor methods... */ 
} 

Cụ thể là: không ai trong số các lĩnh vực được khai báo là final, và phải có một hàm tạo không có đối số để khung công tác Hibernate có thể khởi tạo lớp và thiết lập các trường của nó.

Nhưng đây là điều - tôi thực sự không thích làm cho các lớp học của tôi có thể thay đổi dưới mọi hình thức bất cứ khi nào tôi có thể tránh nó (Java Practices: Đối tượng Immutable làm cho một cuộc tranh luận khá mạnh để làm điều này). Vì vậy, là có bất kỳ cách nào để có được Hibernate để làm việc ngay cả khi tôi đã tuyên bố mỗi cuối cùng của các lĩnh vực '? Tôi hiểu rằng Hibernate sử dụng Reflection để khởi tạo các lớp của nó và do đó cần có khả năng gọi một hàm tạo của một loại nào đó mà không chấp nhận rủi ro nó sẽ chọn hàm tạo sai hoặc truyền giá trị sai cho một trong các tham số của nó, do đó, nó có thể an toàn hơn để gọi hàm tạo no-arg và đặt từng trường một tại một thời điểm. Tuy nhiên, nó không phải là có thể cung cấp các thông tin cần thiết để Hibernate để nó có thể nhanh chóng an toàn các đối tượng không thay đổi?

public class Event { 

    private final Long id; 
    private final String title; 
    private final Date date; 

    public Event(@SetsProperty("id") Long id, 
     @SetsProperty("title") String title, 
     @SetsProperty("date") Date date) { 

     this.id = id; 
     this.title = title; 
     this.date = new Date(date.getTime()); 
    } 

    /* Accessor methods... */ 
} 

Chú thích @SetsProperty tất nhiên là hư cấu, nhưng dường như không nên để xa tầm tay.

Trả lời

5

này nghe có vẻ như nó không phải là một trường hợp sử dụng cho Hibernate, vì nhiều hoạt động nó thực hiện mối quan tâm nhà nước có thể thay đổi:

  • sáp nhập đối tượng
  • nhà nước bẩn kiểm tra
  • xả thay đổi

Điều đó đang được nói, nếu bạn lo ngại về bất biến, bạn có thể chọn cung cấp trình bao bọc xung quanh các đối tượng của mình, với các nhà xây dựng bản sao:

public class FinalEvent { 
    private final Integer id; 

    public FinalEvent(Event event) { 
     id = event.id; 
    } 
} 

Nó có nghĩa là làm việc thêm mặc dù.


Bây giờ tôi đang nghĩ về nó, các phiên ngủ đông thường được gắn chuỗi và khoảng trống này ít nhất một lợi ích của trường cuối cùng - ấn bản an toàn.

Bạn đang tìm kiếm những lợi ích nào khác của các trường cuối cùng?

+1

+1: Ý tưởng tuyệt vời khi sử dụng lớp bao bọc - có vẻ như đây là giải pháp tốt khi cần các lớp/trường cuối cùng. Người ta thậm chí có thể tránh sự mơ hồ mà phiên bản (mutable vs. wrapper) nên được sử dụng bên ngoài bằng cách làm cho phiên bản có thể thay đổi chỉ hiển thị đối với các lớp truy cập dữ liệu. Đối với việc sử dụng cuối cùng, lý do chính của tôi là nó thường chỉ dễ dàng hơn để đảm bảo (chứ không phải giả định) rằng mỗi lĩnh vực được chỉ định chính xác một lần khi xây dựng. Chúng tôi có rất nhiều dữ liệu có ý nghĩa không đổi trong suốt cuộc đời của JVM sử dụng nó, vì vậy sẽ hữu ích khi làm rõ điều này. –

+1

Các trường cuối cùng ngăn người dùng vô tình gán thứ gì đó họ không nên có và giới thiệu một lỗi nhỏ. Nếu bạn biết một cái gì đó sẽ không bao giờ thay đổi, bạn muốn làm cho nó cuối cùng. Xuống đường nếu bạn thấy rằng nó sẽ thay đổi, bạn luôn có thể loại bỏ ràng buộc đó. – corsiKa

13

Đối tượng không thể thay đổi là một đối tượng không có phương pháp sửa đổi trạng thái của nó (tức là trường của nó). Các lĩnh vực không cần phải là cuối cùng. Vì vậy, bạn có thể loại bỏ tất cả các mutators và cấu hình Hibernate để sử dụng các trường acces thay vì accessors hoặc bạn chỉ có thể đánh dấu constructor no-arg và mutators như không được chấp nhận. Đó là một chút giải pháp nhưng tốt hơn là không có gì.

+4

+1: Cảm ơn - điều này cũng hữu ích (loại bỏ các bộ định cư và sử dụng truy cập dựa trên trường) đối với các trường hợp không thể/thực tế để tạo lớp bao bọc. Không thể nói là tôi quá hồi hộp với kiểu Reflection kung-fu đang diễn ra đằng sau hậu trường - các trường riêng tư không thực sự riêng tư và tất cả. Loại làm cho tôi cảm thấy như tôi nên thêm một số thẻ @ReadTheHibernateBookBeforeUsingThisClass cho người dùng (như tôi), những người không quen thuộc với các chi tiết về cách thức hoạt động của Hibernate. –

2

Bạn có thể thực hiện kết quả mong muốn bằng cách sử dụng mẫu Trình xây dựng. Tôi đã đọc một số posting một lúc trước trên Diễn đàn Hibernate thảo luận về ý tưởng đó (mặc dù tôi chưa bao giờ tự mình thực hiện nó ...)

4

Điều này đã khiến tôi mất nhiều thời gian.Một ý tưởng tôi đã cố gắng ra gần đây là điều này - xác định giao diện chỉ đọc cho các lớp mô hình của bạn và có DAO của bạn và bất kỳ nhà máy trả lại những thay vào đó trên đối tượng. Điều đó có nghĩa rằng mặc dù việc thực hiện là có thể thay đổi, một khi nó rời DAO/nhà máy đối tượng nó không còn có thể được tinh chỉnh.

Giống như vậy:

public interface Grape { 
    public Color getColor(); 
} 

public class HibernateGrapeDao { 
    public Grape findGrape(int grapeId) { 
    HibernateGrape grape = hibernate.find(... 
    return grape; 
    } 
} 

class HibernateGrape implements Grape { 
.... 
} 

thậm chí có thể muốn giữ lại các lớp thực hiện gói tin tới các gói dao, để không ai có thể fiddle với họ trực tiếp. Công việc nhiều hơn một chút, nhưng có thể giúp giữ cho mọi thứ sạch hơn trong thời gian dài. Và, rõ ràng, hãy cẩn thận với toàn bộ công bằng/nhận dạng doanh nghiệp.

10

Thực tế trong JDK 1.5+ ngủ đông có thể xử lý (thông qua phản ánh) thay đổi các trường cuối cùng. Tạo một hàm tạo mặc định được bảo vệ() đặt các trường thành một số giá trị mặc định/null, vv ... Hibernate có thể và sẽ ghi đè lên các giá trị đó khi nó khởi tạo đối tượng.

Điều này là tất cả có thể nhờ vào những thay đổi đối với mô hình bộ nhớ Java 1.5 - những thay đổi quan tâm (cho phép cuối cùng không được như vậy cuối cùng) nơi được thực hiện để cho phép tuần tự hóa/deserialization.

public class Event { 

private final Long id; 
private final String title; 
private final Date date; 

// Purely for serialization/deserialization 
protected Event() { 
    id = null; 
    title = null; 
    date = null; 
} 

public Event(Long id, String title, Data date) { 
    this.id = id; 
    this.title = title; 
    this.date = date; 
} 

/* Accessor methods... */ 

}

0

Chú thích lớp học của bạn với @Access (AccessType.FIELD) sau đó bạn có thể làm cho các lĩnh vực của bạn thức. Như thế này:

@Access(AccessType.FIELD) 
public final class Event { 

    private final Long id; 
    private final String title; 
    private final Date date; 

    private Event() { 
     id = null; 
     title = null; 
     date = null; 
    } 

    public Event(Long id, String title, Date date) { 
     this.id = id; 
     this.title = title; 
     this.date = date; 
    } 
}