2010-09-06 25 views
17

Vì tôi đã sử dụng Grails nhiều hơn và nhiều hơn nữa, tôi thấy mình viết mã trong nhiều bộ điều khiển mà thực sự có vẻ như nó phải là một phần của một lớp miền. Đôi khi, mã miền này chứa một cuộc gọi đến một lớp dịch vụ. Ví dụ, gần đây tôi đã viết một phương pháp miền trông giống như sau:Thiết kế xấu có thể gọi dịch vụ Grails từ các đối tượng miền không?

class Purchase { 

    // Injected 
    def paymentService 

    String captureTransactionId 
    Boolean captured 

    // ... 

    def capture() { 
     captureTransactionId = paymentService.capturePurchase(this) 
     captured = captureTransactionId != null 
    } 

Tôi không cảm thấy hoàn toàn dơ bẩn mã này, nhưng tôi chưa thực hiện một nghiên cứu về thực hành thiết kế tốt nhất trong Grails, vì vậy tôi muốn nhận được một số ý kiến.

+0

Nhận xét muộn: khi nào các dịch vụ được tiêm? Ví dụ: nếu bạn tải 10.000 Giao dịch mua từ cơ sở dữ liệu, thì dịch vụ paymentService có được chèn vào chúng không? Hiệu suất sẽ bị ảnh hưởng đáng kể. – wishihadabettername

+0

@ User277434 - Hibernate không thực sự có ý nghĩa để thực hiện loại tải hàng loạt này. Nếu tôi có nhiều bản ghi này để tải cùng một lúc, tôi có thể bỏ qua sử dụng chế độ ngủ đông hoặc sử dụng truy vấn có phép chiếu để tránh tạo đối tượng. –

Trả lời

15

Tôi chuyển qua lại với các nội dung như thế này. Trước Grails, tôi không gặp vấn đề gì với các lớp miền thiếu máu và đưa mọi thứ vào những người giúp đỡ. Lý do lớn tôi thường kết thúc với các lớp thiếu máu là xác nhận. Thật đơn giản để xác nhận tính hợp lệ, độ dài, vv bên trong lớp nhưng tính duy nhất yêu cầu kiểm tra cơ sở dữ liệu và điều đó không liên quan đến một lớp miền (trong một ứng dụng không phải Grails) vì vậy tôi sẽ chuyển nó đến một trình trợ giúp. Bây giờ tôi đã xác nhận ở hai nơi, vì vậy tôi sẽ hợp nhất trong trình trợ giúp và sẽ được để lại với một lớp chỉ có dữ liệu.

Nhưng Grails thay thế nhu cầu DAO bằng cách nối dây trong các phương thức GORM vào các lớp miền và cũng thay thế nhu cầu cho trình xác nhận bằng cách đặt xác nhận trong các lớp miền. Vì vậy, điều này tạo ra các vấn đề khi quyết định logic kinh doanh nào nên đi trong lớp miền và những gì nên ở trong dịch vụ hoặc trợ giúp khác - dịch vụ tạo một nơi tuyệt vời để đặt logic nghiệp vụ có thể cần trong phương thức lớp miền hoặc trình xác thực.

Có nó không phải là OO-thuần túy, có bạn tạo một chu kỳ (dịch vụ gọi lớp miền và lớp miền gọi dịch vụ), không có nó không phải là "cách Spring" nhưng rất nhiều Grails không phải là "Spring đường".

Khớp nối như thế này khiến việc chia ứng dụng trở thành thành phần hoặc plugin để sử dụng lại khó hơn, nhưng việc khai báo dịch vụ với 'def paymentService' sẽ giúp ích rất nhiều do bạn không được kết hợp với tên gói hoặc triển khai.

+0

Có, tôi đã sử dụng các dịch vụ chủ yếu là các thành phần nhỏ và tập trung nói chuyện với các hệ thống bên ngoài và sau đó gọi chúng từ bất kỳ nơi nào có ý nghĩa. Tôi nghĩ rằng họ đang tách ra đủ vì mô hình tiêm mà bạn đã đề cập. Tôi thích điều này tốt hơn nhiều so với kiểu Script giao dịch của mô hình mà @duffymo và @ammoQ dường như đang đề xuất. –

+0

Bạn nói đây không phải là "con đường mùa xuân", nhưng đây là một bài trình bày của người sáng lập Spring, trong đó ông chủ trương làm chính xác điều này: http://www.infoq.com/presentations/rod-johnson-are-we-there- chưa –

+0

Tôi sẽ bênh vực làm việc đó theo bất cứ cách nào nhanh hơn và đơn giản hơn, trong trường hợp này là sử dụng dịch vụ bên trong lớp miền. Làm nó có vẻ đúng trên một cuốn sách, nhưng thành thật mà nói, bạn có thường xuyên sử dụng các lớp miền của bạn cho một ứng dụng khác nhau bằng cách sử dụng cùng một cơ sở dữ liệu không? Ngay cả khi nó trở thành một yêu cầu sau đó, giải quyết vấn đề sau đó, không phải bây giờ. –

3

Tôi không nghĩ rằng các lớp miền/mô hình nên gọi dịch vụ. Nó phải là cách khác 'tròn.

Dịch vụ có thể dàn xếp các dịch vụ khác để hoàn thành trường hợp sử dụng. Tôi nghĩ đó là con đường đúng đắn để đi.

+1

Bạn có thể giải thích lý do đằng sau ý kiến ​​của mình không? Điều gì làm cho nó tốt hơn hoặc tồi tệ hơn để làm điều đó một cách trên khác? –

+0

Tôi đồng ý với duffymo; lý do là nguyên tắc ít ngạc nhiên nhất. Một lớp miền gọi một lớp dịch vụ là đáng ngạc nhiên và một dấu hiệu mạnh mẽ rằng trách nhiệm chưa được gán cho các lớp đúng cách. –

+0

Đó là cách Spring, và Spring là cơ sở cho Grails. – duffymo

3

Tôi chỉ đưa ra ý kiến ​​cá nhân của mình. Vì grails hỗ trợ các dịch vụ tiêm vào các lớp miền một cách tự động (không giống như các dịch vụ tiêm vào các lớp groovy chuẩn mà bạn phải tự cấu hình), tôi đoán rằng nó được dự định sử dụng theo cách đó và do đó không phải là một thực hành tồi.

Ngoài ra nó làm cho mã dễ đọc hơn với một cái gì đó như "myDomainInstance.someUsefulMethod()", hơn "someService.someUsefulMethod (myDomainInstance)" (hy vọng bạn biết ý tôi là gì).

+0

Vâng, tôi biết ý bạn là gì và tôi cũng cảm thấy như vậy. Tôi thấy điều này tương tự như sử dụng một giao diện tách biệt trong Java và có mã miền của bạn gọi các lớp DAO. Mô hình đó dường như đã truyền cảm hứng cho những thứ như GORM, nơi bạn chỉ cần nói với lớp miền để tự lưu. Tôi thấy điều này giống như vậy. Tôi nói với các lớp học thanh toán để nắm bắt chính nó và nó nói chuyện với hệ thống bên ngoài để chăm sóc nó. Theo cách này, có sự ghép nối thấp và tôi đã tránh viết một lớp dịch vụ * Giao dịch-Script kiểu * rất thủ tục. –

0

Tôi không chắc liệu nó đúng hay sai.

Trong trường hợp như ví dụ, việc đi bằng cách này hay cách khác: hãy đặt mã paymentService.capturePurchase() bên trong lớp Mua hàng hoặc bạn có thể đặt tất cả logic vào dịch vụ?

+0

Vì tôi muốn tách riêng các mối quan tâm và duy trì trách nhiệm duy nhất cho các thành phần của tôi. Tôi muốn mã miền để cập nhật logic miền và tôi muốn mã dịch vụ tương tác với hệ thống thanh toán bên ngoài. –

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