2011-09-05 31 views
17

Mặc dù đã nghiên cứu Domain Driven Design trong một thời gian dài hiện nay vẫn còn một số khái niệm cơ bản mà tôi chỉ tìm ra.Gặp khó khăn khi đưa logic thực tế vào lớp miền DDD

Dường như mỗi khi tôi cố gắng thiết kế một giàu domain layer, tôi vẫn cần rất nhiều Domain Services hoặc một dày Application Layer, và tôi kết thúc với một loạt các đơn vị miền gần như thiếu máu không có logic thực trong họ, ngoài từ "GetTotalAmount" và tương tự. Vấn đề chính là các thực thể không nhận thức được các công cụ bên ngoài, và thực hành không tốt là đưa bất cứ thứ gì vào thực thể.

Hãy để tôi đưa ra một số ví dụ:

1. Người dùng đăng ký một dịch vụ. Người dùng được lưu giữ trong cơ sở dữ liệu, một tệp được tạo và lưu (cần thiết cho tài khoản người dùng) và một email xác nhận được gửi đi.

Ví dụ với email xác nhận đã được thảo luận rất nhiều trong các chủ đề khác, nhưng không có kết luận thực sự. Một số gợi ý đặt logic vào một số application service nhận được EmailServiceFileService được tiêm từ infrastructure layer. Nhưng sau đó tôi sẽ có logic kinh doanh bên ngoài miền, phải không? Những người khác khuyên bạn nên tạo một domain service mà được các infrastructure services tiêm - nhưng trong trường hợp đó tôi sẽ cần phải có các giao diện của infrastructure services bên trong domain layer (IEmailServiceIFileService) mà không nhìn quá tốt hoặc (vì domain layer không thể tham khảo các infrastructure layer) . Và những người khác đề xuất triển khai Udi Dahan's Domain Events và sau đó đăng ký dịch vụ EmailService và FileService với các sự kiện đó. Nhưng điều đó có vẻ giống như việc thực hiện rất lỏng lẻo - và điều gì sẽ xảy ra nếu các dịch vụ thất bại? Xin vui lòng cho tôi biết những gì bạn nghĩ là giải pháp đúng ở đây.

2. Bài hát được mua từ cửa hàng nhạc kỹ thuật số. Giỏ hàng đã được dọn sạch. Giao dịch mua được duy trì. Dịch vụ thanh toán được gọi. Một email xác nhận được gửi đi.

Ok, điều này có thể liên quan đến ví dụ đầu tiên. Câu hỏi đặt ra ở đây là ai chịu trách nhiệm dàn xếp giao dịch này? Tất nhiên tôi có thể đặt tất cả mọi thứ trong bộ điều khiển MVC với các dịch vụ tiêm. Nhưng nếu tôi muốn DDD thực thì tất cả logic nghiệp vụ phải nằm trong miền. Nhưng thực thể nào nên có phương thức "Mua"? Song.Purchase()? Order.Purchase()? OrderProcessor.Purchase() (dịch vụ tên miền)? ShoppingCartService.Purchase() (dịch vụ ứng dụng?)

Đây là trường hợp tôi nghĩ rất khó để sử dụng logic nghiệp vụ thực trong các thực thể miền. Nếu thực hành không tốt để tiêm bất cứ thứ gì vào thực thể, làm sao họ có thể làm những thứ khác hơn là kiểm tra trạng thái của chính nó (và trạng thái tổng hợp của nó)?

Tôi hy vọng những ví dụ này đủ rõ ràng để hiển thị các vấn đề tôi đang xử lý.

+0

DDD đề xuất thực hiện các mục 'File' và' Email'.Cơ sở hạ tầng chịu trách nhiệm thực sự tạo một tệp và thực sự gửi email khi các thực thể tương ứng xuất hiện trong Lớp Miền. – Lightman

Trả lời

8

Người dùng đăng ký dịch vụ.Người dùng được lưu giữ trong cơ sở dữ liệu , một tệp được tạo và lưu (cần thiết cho tài khoản người dùng), và email xác nhận được gửi.

Bạn có thể áp dụng Dependency Inversion Principle tại đây. Định nghĩa một giao diện miền như thế này:

void ICanSendConfirmationEmail(EmailAddress address, ...) 

hoặc

void ICanNotifyUserOfSuccessfulRegistration(EmailAddress address, ...) 

Giao diện có thể được sử dụng bởi các lớp miền khác. Triển khai thực hiện giao diện này trong tầng cơ sở hạ tầng, sử dụng các lớp SMTP thực. Tiêm việc triển khai này khi khởi động ứng dụng. Bằng cách này, bạn đã tuyên bố ý định kinh doanh trong mã miền và logic miền của bạn không có tham chiếu trực tiếp đến cơ sở hạ tầng SMTP. Chìa khóa ở đây là tên của giao diện, nó nên được dựa trên ngôn ngữ Ubiquitous.

Bài hát được mua từ cửa hàng nhạc kỹ thuật số. Giỏ hàng bị làm trống. Giao dịch mua được duy trì. Dịch vụ thanh toán được gọi. Xác nhận email được gửi. Ok, điều này có thể liên quan đến ví dụ đầu tiên. Câu hỏi đặt ra ở đây là ai chịu trách nhiệm dàn xếp giao dịch này?

Sử dụng các phương pháp hay nhất OOP để phân công trách nhiệm (GRASP và RẮN). Đơn vị kiểm tra và tái cấu trúc sẽ cung cấp cho bạn một phản hồi thiết kế. Bản thân dàn nhạc có thể là một phần của mỏng Lớp ứng dụng. Từ DDD Layered Architecture:

Tầng ứng dụng: Xác định việc làm phần mềm là phải làm và chỉ đạo các đối tượng miền biểu cảm để làm việc ra vấn đề. Các nhiệm vụ mà lớp này chịu trách nhiệm cho việc kinh doanh hoặc cần thiết cho sự tương tác với các lớp ứng dụng của các hệ thống khác.

Lớp này được giữ mỏng. Nó không chứa quy tắc kinh doanh hoặc kiến ​​thức, nhưng chỉ có tọa độ nhiệm vụ và đại biểu làm việc để cộng tác của các đối tượng miền trong lớp tiếp theo. Nó không có trạng thái phản ánh tình hình kinh doanh, nhưng nó có thể có trạng thái phản ánh tiến độ của một nhiệm vụ cho người dùng hoặc chương trình.

+0

Cảm ơn! Ý tưởng tuyệt vời với giao diện miền. Và sau khi kiểm tra nhiều mẫu DDD hơn, tôi tin rằng tôi không nên lo sợ việc đặt * một số * logic nghiệp vụ vào lớp ứng dụng - chẳng hạn như quản lý thứ tự gọi các đối tượng miền. – lasseschou

+0

Xin chào Dmitry, tôi có một câu hỏi liên quan đến các giao diện miền. Bạn có muốn giới thiệu việc triển khai thực hiện các giao diện miền trực tiếp trên các thực thể miền không? (đó là thực hành tốt?) - hoặc bạn sẽ tạo một dịch vụ miền 'UserService' với một thực thi tiêm, và sau đó gọi dịch vụ đó từ tầng ứng dụng (' UserService.SendConfirmationEmail() ')? Tôi vẫn chưa hiểu rõ cách triển khai giải pháp này. – lasseschou

0

Big phần của bạn yêu cầu có liên quan đến đối tượng thiết kế theo định hướng và phân công trách nhiệm, bạn có thể nghĩ GRASP PatternsThis, bạn có thể được hưởng lợi từ những cuốn sách thiết kế hướng đối tượng, giới thiệu sau đây

Applying UML and Patterns

11

Câu trả lời của Dimitry chỉ ra một số điều cần tìm. Thông thường, bạn dễ dàng tìm thấy chính mình trong kịch bản của mình, với việc chuyển dữ liệu từ db lên GUI thông qua các lớp khác nhau.

Tôi đã được lấy cảm hứng từ lời khuyên đơn giản của Jimmy Nilsson "Đối tượng giá trị, đối tượng Giá trị và nhiều đối tượng Giá trị". Thường thì mọi người có xu hướng tập trung nhiều vào Danh từ và mô hình hóa chúng thành thực thể. Đương nhiên bạn thường gặp khó khăn trong việc tìm kiếm hành vi DDD. Động từ dễ liên kết hơn với hành vi. Một điều tốt là làm cho các Động từ này xuất hiện trong miền của bạn dưới dạng đối tượng Giá trị.

Một số hướng dẫn tôi sử dụng cho bản thân khi cố gắng phát triển miền (phải nói rằng cần có thời gian để xây dựng tên miền phong phú, thường là một số lần lặp lại cấu trúc lại ...):

  • Giảm thiểu tài sản (được/bộ)
  • Sử dụng giá trị các đối tượng càng nhiều càng tốt
  • thể phơi ít nhất bạn có thể. Làm cho miền của bạn tổng hợp các phương thức trực quan.

Đừng quên rằng tên miền của bạn có thể phong phú bằng cách xác thực. Đó chỉ là tên miền của bạn biết cách tiến hành mua hàng và những gì cần thiết.

Tên miền của bạn cũng phải chịu trách nhiệm xác thực khi thực thể của bạn thực hiện chuyển đổi từ một trạng thái khác hai trạng thái khác (xác thực luồng công việc).

tôi sẽ cung cấp cho bạn một số ví dụ: Dưới đây là một bài báo tôi đã viết trên blog của tôi về vấn đề của bạn về miền thiếu máu http://magnusbackeus.wordpress.com/2011/05/31/preventing-anemic-domain-model-where-is-my-model-behaviour/

Tôi cũng có thể thực sự khuyên bạn bài viết blog Jimmy Bogard về việc phê chuẩn tổ chức và sử dụng mô hình Validator cùng với các phương pháp mở rộng. Nó cung cấp cho bạn sự tự do để xác thực những điều cơ sở hạ tầng mà không làm cho miền của bạn bị bẩn: http://lostechies.com/jimmybogard/2007/10/24/entity-validation-with-visitors-and-extension-methods/

Tôi sử dụng các sự kiện miền của Udi với thành công lớn. Bạn cũng có thể làm cho chúng không đồng bộ nếu bạn tin rằng dịch vụ của bạn có thể không thành công. Bạn cũng quấn nó trong một giao dịch (sử dụng khung NServiceBus).

Trong ví dụ đầu tiên của bạn (chỉ cần suy nghĩ ngay bây giờ để có được suy nghĩ của chúng tôi suy nghĩ nhiều hơn về các đối tượng giá trị).

  1. Dịch vụ ứng dụng MusicService.AddSubscriber(User newUser) của bạn nhận cuộc gọi từ người trình bày/bộ điều khiển/WCF với Người dùng mới. Dịch vụ đã nhận được IUserRepositoryIMusicServiceRepository được tiêm vào ctor.
  2. Dịch vụ nhạc "Spotify" được tải thông qua phương thức IMusicServiceRepository
  3. pháp nhân musicService.SignUp(MusicServiceSubscriber newSubsriber) lấy đối tượng Giá trị MusicServiceSubscriber. Đối tượng Giá trị này phải lấy Người dùng và các đối tượng bắt buộc khác trong ctor (các đối tượng giá trị không thay đổi). Ở đây bạn cũng có thể đặt logic/hành vi như xử lý subscriptionId's etc.
  4. Phương thức đăng ký nào cũng thực hiện, nó kích hoạt Sự kiện miền NewSubscriberAddedToMusicService. Nó bị bắt bởi EventHandler HandleNewSubscriberAddedToMusicServiceEvent trong đó có IFileServiceIEmailService được tiêm vào ctor của nó. Việc triển khai trình xử lý này nằm trong lớp Dịch vụ ứng dụng NHƯNG sự kiện được kiểm soát bởi Tên miền và MusicService.SignUp. Điều này có nghĩa là Miền nằm trong tầm kiểm soát. Eventhandler tạo tệp và gửi email.

Bạn có thể duy trì người dùng thông qua trình xử lý sự kiện HOẶC thực hiện phương thức MusicService.AddSubscriber(...) cho điều này. Cả hai sẽ làm điều này thông qua IUserRepository nhưng đó là một vấn đề của hương vị và có lẽ nó sẽ phản ánh tên miền thực tế như thế nào.

Cuối cùng ... Tôi hy vọng bạn nắm bắt điều gì đó ở trên ... dù sao đi nữa. Quan trọng nhất là bắt đầu thêm các phương thức "Động từ" vào thực thể và cộng tác. Bạn cũng có thể có đối tượng trong miền của mình không tồn tại, chúng chỉ ở đó để dàn xếp giữa một số thực thể miền và có thể lưu trữ các thuật toán, v.v.

+0

Xin chào - cảm ơn một loạt các ý tưởng tuyệt vời của bạn. Quá tệ, tôi chỉ có thể đánh dấu một câu trả lời, bởi vì bài đăng này dẫn tôi đi đúng hướng, giống như của Dmitry. Chỉ một câu hỏi - nếu bạn đang sử dụng các sự kiện miền, có lẽ thậm chí không đồng bộ - làm cách nào để bạn xử lý tình huống mà không thể gửi thông báo qua email? Điều đó sẽ chỉ là một số xử lý ngoại lệ tùy chỉnh trong trình xử lý sự kiện? – lasseschou

+0

Nếu bạn sử dụng NServiceBus làm nền tảng, nó sử dụng các giao dịch MSDTC, vì vậy nếu mã của bạn không thành công thì thư sẽ được khôi phục (tôi đoán). Tuy nhiên Nếu mọi thứ hoạt động và bạn có tin nhắn của bạn trong hàng đợi và sau đó máy chủ SMTP hết thời gian do lỗi máy chủ ... tốt. Sau đó, bạn phải nắm bắt thông báo lỗi đó và thông báo cho người dùng về lỗi thư. Nhưng NserviceBus sẽ cố gắng gửi email này 5 (mặc định 5) lần. Sau đó, bạn có thể báo cáo lỗi cho hàng đợi lỗi. Sau đó, bạn có thể xử lý thông báo lỗi đó và thông báo cho người dùng về lỗi. –

+0

ok, cảm ơn Magnus. Heja từ denmark! – lasseschou

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