Đối tượng kinh doanh - Container hay chức năng?


19

Đây là một câu hỏi tôi đã hỏi một lúc trước về SO, nhưng nó có thể được thảo luận tốt hơn ở đây ...

Nơi tôi làm việc, chúng tôi đã qua lại về chủ đề này một số lần và đang tìm kiếm một kiểm tra vệ sinh. Đây là câu hỏi: Các đối tượng kinh doanh nên là các thùng chứa dữ liệu (giống như các DTO ) hay chúng cũng nên chứa logic có thể thực hiện một số chức năng trên đối tượng đó.

Ví dụ - Lấy một đối tượng khách hàng, nó có thể chứa một số thuộc tính phổ biến (Tên, Id, v.v.), đối tượng khách hàng đó có nên bao gồm các hàm (Lưu, Calc, v.v.) không?

Một dòng lý luận nói tách biệt đối tượng khỏi chức năng (nguyên tắc chịu trách nhiệm duy nhất) và đưa chức năng vào lớp hoặc đối tượng Business Logic.

Một dòng lý luận khác nói, không, nếu tôi có một đối tượng khách hàng, tôi chỉ muốn gọi cho Khách hàng. Lưu lại và được thực hiện với nó. Tại sao tôi cần biết về một lớp khác để cứu khách hàng nếu tôi tiêu thụ đối tượng?

Hai dự án cuối cùng của chúng tôi đã có các đối tượng tách khỏi chức năng, nhưng cuộc tranh luận đã được đưa ra một lần nữa về một dự án mới.

Mà có ý nghĩa hơn và tại sao ??


1
Bạn có thể cho chúng tôi biết thêm về dự án của bạn? Bản chất của dự án của bạn sẽ xác định giải pháp nào là tốt hơn.

Câu trả lời:


5

Nếu bạn cho rằng Khách hàng là một phần của mô hình miền, thì điều đó có ý nghĩa (đặc biệt là trong bối cảnh DDD nhưng không giới hạn ở đó) để có cả thuộc tính và hoạt động cho đối tượng đó.

Tuy nhiên, như đã nói, tôi nghĩ rằng ví dụ bạn đã sử dụng là một ví dụ kém và là nguyên nhân của tranh luận. Nếu bạn đang nói về sự kiên trì, thì Khách hàng thường không tự 'tiết kiệm'; bất cứ điều gì bạn đang sử dụng cho sự kiên trì sẽ. Nó có ý nghĩa rằng bất kỳ loại kiên trì nên thuộc về lớp / phân vùng kiên trì. Đây thường là suy nghĩ đằng sau mẫu kho lưu trữ. ** Một phương thức như Customer.UpTHERWarcill () hoặc Customer.PromoteToPreferred () làm cho đối số rõ ràng hơn.

Điều này cũng không loại bỏ khả năng có DTOs . Ví dụ, hãy xem xét tình huống bạn sẽ chuyển thông tin khách hàng đến một dịch vụ từ xa. Việc khách hàng tự tạo ra một DTO để vận chuyển có thể không có ý nghĩa, đó là một mối quan tâm về kiến ​​trúc, nhưng trường hợp có thể được thực hiện cho nó trong sự kiên trì hoặc lớp / phân vùng / mã / những gì bạn có. Trong trường hợp đó, một đối tượng như vậy có các phương thức giống như thế này

public static CustomerDTO GetDTO(Customer c) { /* ... */ }

public static Customer GetCustomer(CustomerDTO cdto) { /* ... */ }

Vì vậy, tóm lại, sẽ có ý nghĩa hoàn hảo khi có các hoạt động trên một đối tượng miền phù hợp với các hoạt động logic trong miền.

Google cho 'Sự thiếu hiểu biết dai dẳng' cho một số cuộc thảo luận tốt về vấn đề này ( câu hỏi SO này và câu trả lời được chấp nhận của nó là một nơi tốt để bắt đầu).

** Điều này có một chút nhầm lẫn với một số phần mềm OR / M nhất định mà bạn buộc phải kế thừa từ một cơ sở liên tục có phương pháp 'Lưu'.


3

Tôi thực sự vừa mới làm lại một số mã để tách các đối tượng khỏi dữ liệu. Lý do là dữ liệu được lấy thông qua một dịch vụ riêng biệt và việc truyền dữ liệu thô đến / từ máy chủ thay vì chuyển toàn bộ đối tượng qua lại và phải xử lý các lỗi xác thực trên máy chủ sẽ dễ dàng hơn nhiều.

Đối với các dự án nhỏ, có các đối tượng chứa logic và dữ liệu kinh doanh của chúng có thể tốt, nhưng đối với các dự án lớn hoặc các dự án có thể mở rộng theo thời gian, tôi chắc chắn sẽ tách các lớp.


3

Tôi nghĩ cả hai cách thực hiện đều có thể có lợi ích của chúng, nhưng tôi sẽ xem xét nó từ quan điểm hướng đối tượng hoặc hướng theo miền: trách nhiệm của các lớp và đối tượng khác nhau là gì.

Vì vậy, tôi sẽ tự hỏi mình điều này, trong trường hợp cụ thể của bạn: khách hàng có nên biết cách tự cứu mình không?

Đối với tôi, câu trả lời sẽ là không: về mặt logic với tôi nó không có ý nghĩa gì, và khách hàng không cần phải biết bất cứ điều gì về bất kỳ khuôn khổ kiên trì nào cả (tách trách nhiệm).

Đối với các ví dụ của SnOrfus với Customer.UpgradWarcill () hoặc Customer.PromoteToPreferred (), rõ ràng chúng có định hướng logic kinh doanh nhiều hơn so với Customer.Save (). Có nhiều cách tiếp cận khác nhau, nhưng một lần nữa nếu bạn tự hỏi liệu khách hàng có được phép nâng cấp bảo hành của mình không, câu trả lời có thể là có hoặc không, tùy thuộc vào cách bạn nhìn vào nó:

  • có: tất nhiên khách hàng có thể nâng cấp bảo hành của mình
  • không: một khách hàng có thể yêu cầu được nâng cấp, nhưng việc nâng cấp được thực hiện bởi người khác

Quay lại câu hỏi ban đầu của bạn; cách nào có ý nghĩa hơn có thể sẽ phụ thuộc vào người bạn hỏi và phương pháp ưa thích của họ, nhưng điều quan trọng nhất có lẽ là tuân theo một cách làm.

Tuy nhiên, theo kinh nghiệm của tôi, việc tách dữ liệu và logic (kinh doanh) làm cho kiến ​​trúc đơn giản hơn, mặc dù không thú vị bằng.


2

Tôi nghĩ bạn đang nói cụ thể về sự khác biệt giữa ActiveRecordmẫu và Repositorymẫu. Trước đây, các thực thể biết cách kiên trì và sau này, kho lưu trữ biết về sự bền bỉ. Tôi nghĩ rằng sau này cung cấp một sự tách biệt tốt hơn của mối quan tâm.

Theo nghĩa rộng hơn, nếu các thực thể hoạt động giống như cấu trúc dữ liệu, thì chúng không nên có hành vi, nhưng nếu chúng có hành vi, thì chúng không nên được sử dụng như cấu trúc dữ liệu. Thí dụ:

Cấu trúc dữ liệu:

class CustomerController
{
    public int MostRecentOrderLines(Customer customer)
    {
        var o = (from order in customer.Orders
                orderby order.OrderDate desc
                select order).First();
        return o.OrderLines.ToList().Count;
    }
}

Cấu trúc phi dữ liệu:

class Customer
{
    public int MostRecentOrderLines()
    {
        // ... same ...
    }
}

Trong trường hợp đầu tiên, bạn có thể điều hướng cây cấu trúc dữ liệu của mô hình của mình mà không gặp sự cố, từ bất kỳ đâu trong mã làm việc của bạn và điều đó không sao, vì bạn đang coi nó như cấu trúc dữ liệu. Trong trường hợp sau, Khách hàng giống như một dịch vụ cho một khách hàng nhất định, vì vậy bạn không nên gọi các phương thức trên kết quả. Tất cả những điều bạn muốn biết về Khách hàng nên có sẵn bằng cách gọi một phương thức trên đối tượng Khách hàng.

Vì vậy, bạn muốn thực thể của bạn là cấu trúc dữ liệu hoặc dịch vụ? Để thống nhất, có vẻ tốt hơn để gắn bó với một. Trong trường hợp trước, hãy đặt logic "dịch vụ" của bạn ở một nơi khác, không phải trong thực thể.


1

Tôi thực sự không thể trả lời câu hỏi của bạn nhưng tôi thấy buồn cười vì chúng tôi cũng đang thảo luận về một trong những dự án của chúng tôi ở trường. Bản thân tôi muốn tách biệt logic từ dữ liệu. Nhưng nhiều bạn cùng lớp của tôi nói rằng đối tượng phải chứa tất cả logic VÀ dữ liệu.

Tôi sẽ cố gắng hè hóa những sự thật họ đưa ra:

  • Một đối tượng lớp nghiệp vụ đại diện cho một thứ, vì vậy tất cả dữ liệu VÀ logic nên được chứa. (ví dụ: nếu bạn muốn mở một cánh cửa, bạn tự làm điều đó, bạn không hỏi người khác. Ví dụ xấu tôi biết)

  • Dễ hiểu hơn về mã và chức năng của một đối tượng bu.

  • Ít phức tạp hơn trong thiết kế

Tôi đang nói với họ rằng họ lười biếng và tôi sẽ làm như thế này:

  • Có lớp kinh doanh đại diện cho mọi thứ, vì vậy nó giữ dữ liệu. Nhưng cảm thấy sai lầm khi tự cứu mình, hoặc thậm chí là sao chép. Bạn không thể làm điều đó trong rl.

  • Làm cho đối tượng chịu trách nhiệm cho mọi thứ làm cho nó không tốt cho độ bền và khả năng bảo trì trong tương lai. Nếu bạn có một lớp riêng biệt chịu trách nhiệm lưu, nếu bạn thêm một đối tượng mới vào thiết kế, bạn có thể dễ dàng thực hiện chức năng lưu của nó. thay vì mã hóa tất cả một lần nữa trong lớp đó.

  • Bằng cách có một đối tượng có thể duy trì dữ liệu, đối tượng đó có thể giữ kết nối cơ sở dữ liệu và tất cả lưu lượng truy cập cơ sở dữ liệu được hướng dẫn tại đối tượng đó. (về cơ bản là lớp dữ liệu của nó) nếu không tất cả các đối tượng Business sẽ phải giữ kết nối. (có thêm độ phức tạp)

Cách này hay cách khác, tôi sẽ hỏi một giáo viên. Khi tôi đã làm điều đó, tôi cũng sẽ đăng câu trả lời của anh ấy ở đây nếu bạn muốn. ;)

chỉnh sửa:

Tôi quên đề cập đến dự án này là về một cửa hàng sách.


Bạn cùng lớp của bạn là đúng, ngoại trừ việc họ nhầm lẫn logic kinh doanh với các dạng logic khác (trong trường hợp này là logic kiến ​​trúc hoặc tính bền vững).
Steven Evers

1

Câu trả lời thực sự sẽ phụ thuộc vào kiến ​​trúc / thiết kế của bạn là gì - một kiến ​​trúc DDD với mô hình miền sẽ rất khác so với mô hình tập trung vào dữ liệu CRUD khi nói đến thiết kế đối tượng.

Tuy nhiên, nói chung, hãy nhớ rằng trong thiết kế hướng đối tượng, bạn đang cố gắng gói gọn trạng thái và phơi bày hành vi. Điều này có nghĩa là bạn thường sẽ cố gắng để trạng thái được liên kết với một hành vi càng gần với hành vi đó - khi bạn không thực hiện điều này, bạn buộc phải phơi bày trạng thái này dưới hình thức này hay hình thức khác.

Trong mô hình miền, bạn muốn tách mô hình kinh doanh khỏi các mối quan tâm về cơ sở hạ tầng - vì vậy bạn hoàn toàn muốn tránh các phương thức như '.Save'. Tôi không nhớ lần cuối cùng tôi "cứu" một khách hàng trong đời thực!

Trong một ứng dụng CRUD thì dữ liệu là công dân hạng nhất nên ".Save" là hoàn toàn phù hợp.

Hầu hết các ứng dụng trong thế giới thực khá lớn sẽ có sự kết hợp của các mô hình này - mô hình miền nơi có các quy tắc kinh doanh thay đổi nhanh chóng hoặc phức tạp, DTO để chuyển dữ liệu qua các ranh giới, CRUD (hoặc một cái gì đó giữa CRUD và mô hình miền, chẳng hạn như Activerecord) ở nơi khác. Không có một kích thước phù hợp với tất cả các quy tắc.


0

Tôi đã suy nghĩ về cùng một câu hỏi trong một thời gian - Tôi nghĩ rằng thành phần dữ liệu và thành phần logic phải tách biệt. Tôi tin điều này bởi vì nó đưa bạn vào đúng khung suy nghĩ liên quan đến logic kinh doanh như một giao diện cho dữ liệu cung cấp ý nghĩa.

Tôi cũng đã sửa đổi quan điểm của Scott Whitlock từ phía trên (ngoại trừ tôi không có điểm nào là thành viên mới), các lớp logic dữ liệu hoặc kinh doanh không thực sự phải lo lắng về việc đối tượng được lưu trữ liên tục như thế nào.

Điều đó đang được nói, nếu bạn đang giao dịch với một sản phẩm hiện có, miễn là bạn có giao diện hợp đồng sạch sẽ - điều đó cũng ổn và có thể duy trì được ...

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.