2016-03-22 11 views
7

Tôi đang ở trong một tình huống rất cụ thể với một trong các lớp tôi đang mã hóa. Tôi có lớp này gọi là User trông như thế này:Mẫu thiết kế - Cách thực thi các thuộc tính đối tượng chỉ trong một số trường hợp (mẫu Builder, Dependency Injection)

public class User { 
    private long id; // + getters and setters 
    private boolean isDeletable; // + getters and setters 
    private String name; // + getters and setters 
    private String password; // + getters and setters 
    private String email; // + getters and setters 
    private String authenticationRealm; // + getters and setters 
    private String displayName; // + getters and setters 
    private Date deletedDate; // + getters and setters 
} 

Trong mã của tôi có một số tình huống mà tôi chỉ cần một đối tượng rỗng của các loại User và do đó chỉ cần xây dựng nó bằng cách sử dụng constructor mặc định: new User().

Tuy nhiên, tôi có một lớp khác được gọi là CreateUserRequest mô hình yêu cầu REST để tạo người dùng trong máy chủ. Trọng tải tối thiểu phải chứa các thuộc tính name, password, emailauthenticationRealm được gửi ở định dạng JSON.

Ngay bây giờ tôi đang xử lý này bằng cách kiểm tra các thông số trong constructor của yêu cầu:

public CreateUserRequest(User user) { 
    if(user.getName() == null || user.getPassword() == null || user.getEmail() == null || user.getAuthenticationRealm() == null) 
     throw new RuntimeException("Not enough attributes in User object. Minimum: name, password, e-mail and authentication realm."); 
} 

này đang làm việc OK nhưng cái gì là ngứa ... Tôi muốn thực hiện điều này một cách an toàn hơn , do đó, mã sẽ thực thi các thuộc tính được phổ biến mà không có khả năng xảy ra ngoại lệ.

Tôi cảm thấy như phải có cách tốt hơn để làm điều này với mẫu thiết kế. Tôi nghĩ về việc tạo ra một lớp học UserRequestBuilder, nhưng điều đó cũng có thể ngụ ý ném một ngoại lệ trong phương pháp build() (nếu không, có cách nào tôi có thể đảm bảo rằng các thuộc tính được điền trước build()?). Việc tiêm phụ thuộc cũng có vẻ giống như một khả năng, nhưng tôi không chắc chắn làm thế nào tôi sẽ đặt nó vào vị trí trong ví dụ cụ thể này ...

Bất kỳ suy nghĩ nào?

+3

Âm thanh giống như một đối tượng khác, đối tượng CreateUser có thể có một hàm tạo và xác thực các giá trị được cung cấp. Bất kỳ lý do nào họ phải dựa trên cùng một lớp vì họ đang thực hiện hai nhiệm vụ khác nhau? – dbugger

+1

Suy nghĩ tức thì của tôi sẽ thêm phương thức isValidUserRequest() mới vào lớp User. Nghĩ rằng lớp người dùng nên tự quyết định xem nó có hợp lệ hay không để sử dụng theo yêu cầu. –

+0

Cảm ơn nhận xét @dbugger. Có - một số cuộc gọi REST hoặc sản xuất hoặc tiêu thụ các đối tượng JSON với cùng thuộc tính của lớp 'User' (tức là lớp User đại diện cho một thực thể từ xa). Các lớp học không thực sự thực hiện các nhiệm vụ khác nhau. Lớp 'CreateUserRequest' xây dựng một cuộc gọi REST chuyển một đối tượng' User' trong tải trọng của nó theo định dạng JSON. – Phil

Trả lời

7

Cách tạo các dịch vụ REST của bạn hoạt động trên Người dùng DTO? (Tất nhiên, UserDTO có thể được thay thế bằng một lớp con của Người dùng).

Bạn có thể chú thích các trường, bộ đặt hoặc tham số hàm tạo trên UserDTO với @NonNull và có cảnh báo trình biên dịch vấn đề Checker Framework khi truyền giá trị null thay vì mật khẩu tên, email, v.v. tới UserDTO.

Sử dụng một khuôn khổ như Mapstruct, ánh xạ giữa các DTOs dịch vụ REST và các đối tượng phụ trợ là rất dễ dàng:

@Mapper 
public interface UserMapper { 

    public static final UserMapper INSTANCE = Mappers.getMapper(UserMapper.class); 

    UserDTO map(User user); 

    User map(UserDTO userDTO); 
} 

Trên mã sẽ khi biên dịch tạo ra một thực hiện UserMapper, với mã autogenerated cho các phương pháp quy định (- và mã được tạo tự động chỉ đơn giản là cặp các getters và setters được đặt tên tương tự. Bạn có thể tự làm điều này, nhưng với nhiều DTO/Entities trở nên tốn thời gian và nhàm chán).

Trong DTO, bạn có thể loại trừ tất cả các trường mà bạn không muốn hiển thị.

Ps. Việc sử dụng riêng của tôi ở trên được đề cập là: Tôi đang tạo một máy chủ REST dựa trên Jersey, tức là việc triển khai tham chiếu của JAX-RS. Dự án này, gọi nó là A, chỉ biết về DTO. Các phương thức REST gọi vào một dự án B khác, lấy các đối tượng từ cơ sở dữ liệu và ánh xạ chúng tới DTO tương ứng, sau đó được trả về cho dự án A. Một phần lý do cho mẫu này là các thực thể của dự án B vì lý do lịch sử lộn xộn với các phương pháp/chức năng, không nên tiếp xúc với dự án A.Đối với kiểm tra sanity (JSON to DTO), jersey hỗ trợ Bean Validation, có nghĩa là, khuôn khổ sẽ xác nhận hợp lệ mỗi bean đầu vào của tài nguyên còn lại nếu chúng được chú thích bằng @Valid. Cũng có thể tạo chú thích tùy chỉnh của riêng bạn, được xác định bằng ConstraintValidator. Khung công tác xác nhận bean sẽ kiểm tra các ràng buộc này trên các tham số phương thức REST của chú thích đã được chú thích. Xem https://jersey.java.net/documentation/latest/bean-validation.html#d0e13690

+0

Cách tiếp cận rất thú vị, @Hervian. Tôi sẽ thử nó và đánh dấu nó như một câu trả lời nếu nó hoạt động. Cảm ơn bạn. – Phil

+0

Tôi theo một cách tiếp cận rất giống nhau và nó hoạt động. Cảm ơn. – Phil

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