Tránh các đối tượng miền cồng kềnh


12

Chúng tôi đang cố gắng di chuyển dữ liệu từ lớp Dịch vụ cồng kềnh của mình sang lớp Miền bằng cách sử dụng phương pháp DDD. Chúng tôi hiện có rất nhiều logic kinh doanh trong các dịch vụ của mình, được trải rộng khắp mọi nơi và không được hưởng lợi từ sự kế thừa.

Chúng tôi có một lớp Miền trung tâm, là trọng tâm của hầu hết công việc của chúng tôi - Giao dịch. Đối tượng Trade sẽ biết cách tự định giá, cách ước tính rủi ro, xác thực chính nó, v.v. Sau đó chúng ta có thể thay thế các điều kiện bằng đa hình. Ví dụ: SimpleTrade sẽ tự định giá theo một cách, nhưng ComplexTrade sẽ tự định giá theo cách khác.

Tuy nhiên, chúng tôi lo lắng rằng điều này sẽ làm nở (các) lớp Trade. Nó thực sự nên chịu trách nhiệm xử lý riêng nhưng quy mô lớp sẽ tăng theo cấp số nhân khi có thêm nhiều tính năng được thêm vào.

Vì vậy, chúng tôi có các lựa chọn:

  1. Đặt logic xử lý trong lớp Trade. Xử lý logic bây giờ là đa hình dựa trên loại giao dịch, nhưng lớp Trade hiện có nhiều phản hồi (giá cả, rủi ro, v.v.) và lớn
  2. Đặt logic xử lý vào lớp khác như TradePricingService. Không còn đa hình với cây thừa kế Trade, nhưng các lớp nhỏ hơn và dễ kiểm tra hơn.

Điều gì sẽ là cách tiếp cận được đề xuất?


Không có vấn đề gì - Tôi rất vui khi chấp nhận di chuyển!

1
Cảnh giác với điều ngược lại: martinfowler.com/bliki/AnemiaDomainModel.html
TrueWill

1
"Quy mô lớp học sẽ tăng theo cấp số nhân khi có thêm nhiều tính năng được thêm vào" - bất kỳ lập trình viên nào cũng nên biết rõ hơn là sử dụng sai từ "theo cấp số nhân" như thế.
Michael Borgwardt

@Piskvor thật là ngu ngốc
Arnis Lapsa

@Arni L.: Cảm ơn bạn đã bình luận chu đáo. Lưu ý rằng đây là, trích dẫn, "di chuyển từ stackoverflow.com 22 tháng 11 lúc 22 giờ 19", cùng với nhận xét của tôi. Bây giờ tôi đã xóa nhận xét của mình rằng "điều này sẽ tốt hơn cho các lập trình viên.SE"; Bây giờ, bạn có bất cứ điều gì để thêm, hoặc đó là ý tưởng duy nhất bạn muốn bày tỏ?
Piskvor rời khỏi tòa nhà

Câu trả lời:


8

Nếu bạn đang sử dụng Domain Driven, hãy xem xét việc coi lớp Trade của bạn là một gốc tổng hợp và phân chia trách nhiệm của nó sang các lớp khác.

Bạn không muốn kết thúc với một lớp con Trade cho mỗi kết hợp giá và rủi ro, vì vậy một Trade có thể chứa các đối tượng Giá và Rủi ro (thành phần). Các đối tượng Giá và Rủi ro thực hiện các tính toán thực tế, nhưng không thể nhìn thấy đối với bất kỳ lớp nào ngoại trừ Giao dịch. Bạn có thể giảm quy mô của Trade, trong khi không để lộ các lớp mới của mình ra thế giới bên ngoài.

Cố gắng sử dụng thành phần để tránh cây thừa kế lớn. Quá nhiều sự kế thừa có thể dẫn đến các tình huống mà bạn cố gắng đánh giày trong hành vi không thực sự phù hợp với mô hình. Tốt hơn là kéo những trách nhiệm đó ra một lớp mới.


Tôi đồng ý. Suy nghĩ về các đối tượng theo các hành vi hình thành nên giải pháp (Giá cả, Rủi ro rủi ro) thay vì cố gắng mô hình hóa vấn đề để tránh các lớp nguyên khối này.
Hội trường Garrett

Cũng đồng ý. Thành phần, rất nhiều lớp nhỏ hơn với các trách nhiệm cụ thể, đơn lẻ, hạn chế sử dụng các phương thức riêng tư, nhiều giao diện hạnh phúc, v.v.
Ian

4

Câu hỏi của bạn chắc chắn khiến tôi nghĩ về Mô hình Chiến lược . Sau đó, bạn có thể trao đổi trong các chiến lược giao dịch / giá khác nhau, tương tự như những gì bạn đang gọi a TradePricingService.

Tôi chắc chắn nghĩ rằng lời khuyên bạn sẽ nhận được ở đây là sử dụng bố cục thay vì kế thừa.


2

Một giải pháp khả thi tôi đã sử dụng trong trường hợp tương tự, đó là mẫu thiết kế bộ điều hợp (trang được tham chiếu chứa rất nhiều mã mẫu). Có thể kết hợp với mẫu thiết kế ủy nhiệm để dễ dàng truy cập vào các phương thức chính.

Về cơ bản, bạn chia chức năng của Trader thành một số khu vực khác nhau - ví dụ: xử lý giá cả, rủi ro, xác nhận tất cả có thể là các lĩnh vực khác nhau. Đối với mỗi khu vực, sau đó bạn có thể triển khai một hệ thống phân cấp lớp riêng biệt xử lý chức năng chính xác đó trong các biến thể cần thiết khác nhau - tất cả giao diện chung cho từng khu vực. Lớp Trader chính sau đó được giảm xuống thành dữ liệu cơ bản nhất và các tham chiếu đến một số đối tượng xử lý, có thể được xây dựng khi cần. Giống

interface IPriceCalculator {
  double getPrice(ITrader t);
}
interface ITrader {
  IPriceCalculator getPriceCalculator();
}
class Tracer implements ITrader {
  private IPriceCalculator myPriceCalculator = null;
  IPriceCalculator getPriceCalculator() {
    if (myPriceCalculator == null)
      myPriceCalculator = PriceCalculatorFactory.get(this);
    return myPriceCalculator;
  }
}

Một lợi thế lớn của phương pháp này, là sự kết hợp có thể có của giá và ricks hoàn toàn tách biệt và do đó có thể được kết hợp khi cần thiết. Điều này khá khó khăn với sự kế thừa một luồng của hầu hết các ngôn ngữ lập trình. Quyết định sử dụng kết hợp nào thậm chí có thể được tính rất muộn :-)

Tôi thường cố gắng giữ các lớp bộ điều hợp - ví dụ: các lớp con IPriceCalculatorở trên - không trạng thái. Tức là các lớp này không được chứa bất kỳ dữ liệu cục bộ nào nếu có thể, để giảm số lượng phiên bản phải được tạo. Vì vậy, tôi thường cung cấp đối tượng thích nghi chính làm đối số trong tất cả các phương thức - như ở getPrice(ITrader)trên.


2

không thể nói nhiều về tên miền của bạn, nhưng

Chúng tôi có một lớp Miền trung tâm, là trọng tâm của hầu hết công việc của chúng tôi - Giao dịch.

... đó là một mùi đối với tôi. Có lẽ tôi sẽ cố gắng phác thảo các trách nhiệm khác nhau của lớp và cuối cùng phân tách nó thành các tập hợp khác nhau. Các uẩn sau đó sẽ được thiết kế xung quanh vai trò và / hoặc quan điểm của các bên liên quan / chuyên gia về lĩnh vực liên quan. Nếu Giá và Rủi ro có liên quan đến cùng một trường hợp hành vi / sử dụng, thì có lẽ chúng thuộc cùng một tổng hợp. Nhưng nếu chúng tách rời, chúng có thể thuộc các tập hợp riêng.

Có thể RiskEvalval có thể là một thực thể riêng biệt trong miền của bạn, cuối cùng với một vòng đời cụ thể (tôi thực sự không thể nói, tôi chỉ đang suy đoán ... bạn biết tên miền của bạn, tôi không), nhưng điều quan trọng là tạo ra các khái niệm ngầm rõ ràng và để tránh khớp nối không phải do hành vi, mà chỉ bởi khớp nối dữ liệu cũ.

Nói chung, tôi nghĩ về hành vi dự kiến ​​và các vòng đời khác nhau của các thành phần liên quan. Chỉ cần thêm hành vi trên đầu dữ liệu được nhóm sẽ tạo ra các đối tượng cồng kềnh. Nhưng dữ liệu đã được nhóm theo một thiết kế dựa trên dữ liệu hiện có, do đó không cần phải tuân theo điều đó.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.