2009-05-05 36 views
24

Một điều tôi thấy trong một số ứng dụng doanh nghiệp DDD mà tôi làm việc, là việc sử dụng các giao diện giống hệt với các thực thể miền, với ánh xạ một đối một các đặc tính và chức năng. Thật vậy, một đối tượng miền luôn được sử dụng thông qua giao diện một-một, và tất cả các thực thể miền đều có giao diện một-một trong kiểu này.Có đang sử dụng giao diện một-một với thực thể miền hay không? Tại sao?

Ví dụ:

đối tượng miền tài khoản:

public class Account : IAccount 
{ 
    public string Name {get;set;} 
    //...some more fields that are also in IAccount 
    public decimal Balance {get;set;} 
} 

Và nó phù hợp với giao diện

public interface IAccount 
{ 
    string Name {get;set;} 
    //... all the fields in Account 
    decimal Balance {get;set;} 
} 

Nhưng gần đây tôi đã trở thành ngày càng bị thuyết phục rằng đây là, trên thực tế, một chất chống -mẫu.
Tôi đã chạy nó bởi một số kiến ​​trúc sư trong cộng đồng nguồn mở, và họ nói rằng điều này được dựa trên những lỗi thiết kế hoặc sai sót, ở đâu đó trong chuỗi thiết kế.

Vì vậy, tôi nói với đồng nghiệp của mình rằng họ nên thoát khỏi việc tạo giao diện cho các đối tượng Miền. Bởi vì không có mục đích cho họ, và bạn phải cập nhật giao diện bất cứ khi nào bạn cập nhật các thực thể miền. Đầu tiên, tuyên bố đã được thực hiện rằng các giao diện này cung cấp 'tách', nhưng tôi phản đối vì các giao diện có mối quan hệ một-một với các thực thể miền mà chúng không thực sự phân tách, thay đổi giao diện có nghĩa là một thay đổi trong thực thể tên miền và ngược lại.

Khiếu nại tiếp theo là chúng tôi cần giao diện cho mục đích thử nghiệm. Truy cập của tôi là Rhino-mocks cung cấp cho việc chế nhạo và stubbing của các lớp bê tông. Nhưng họ cho rằng Rhino-mocks gặp rắc rối với các lớp bê tông. Tôi không biết nếu tôi mua nó, ngay cả khi tê giác-mocks có rắc rối với các lớp cụ thể, điều đó không nhất thiết có nghĩa là chúng ta nên sử dụng giao diện cho các thực thể miền.

Vì vậy, tôi rất tò mò:

Tại sao bạn có giao diện một-một cho các thực thể miền của mình?

Tại sao không?

Tại sao thực tiễn tốt hay xấu?

Cảm ơn bạn đã đọc!

EDIT: Tôi nên lưu ý rằng tôi sử dụng giao diện mọi lúc, và tôi tin rằng nếu nó được gọi là tôi sẽ sử dụng giao diện khi thả mũ. Nhưng tôi đặc biệt đề cập đến các thực thể miền với giao diện một-một.

+0

AFAIK tê giác Mocks không thể thử nghiệm các phương thức lớp bê tông trừ khi chúng có thể được ghi đè. Vì vậy, bạn sẽ phải làm cho tất cả các phương thức đối tượng miền ảo. Không tốt. –

+0

Liên quan: http://stackoverflow.com/questions/2659366/java-interfaces-methodology-should-every-class-implement-an-interface – jaco0646

Trả lời

8

Thực tiễn không đúng như được mô tả, nhưng ...

Không có lý do cụ thể nào cho giao diện của bạn cần khác với thực thể miền của bạn; đôi khi nó thực sự là bản đồ đúng. Nhưng điều đáng ngờ là luôn luôn như vậy. Điểm đáng lo ngại là có một câu hỏi liệu các giao diện có được thiết kế thực sự hay không hoặc liệu chúng có bị ném vào chỗ thiếu thời gian/lười biếng hay không.

Để sử dụng ví dụ của bạn, giao diện IAccount bạn mô tả sẽ hiển thị getters và setters trên đối tượng Account; có vẻ hơi kỳ quặc và không chắc rằng mọi thứ sử dụng Tài khoản sẽ cần phải đặt số dư trên tài khoản và rằng quyền ngụ ý đó được chỉ định ở cấp độ giao diện đó.Không có chỗ nào trong hệ thống của bạn mà bạn muốn chỉ kiểm tra nhưng không đặt số dư Tài khoản?

+0

Có, có nhiều quân khu vực mà toàn bộ giao diện không được sử dụng. Trong thực tế nó là nhiều hơn trường hợp một phần của giao diện không được sử dụng, hơn là. –

+1

Vâng, các ứng dụng không phải là thiết kế theo định hướng miền; đó là thiết kế dựa trên dữ liệu thuần túy. Và có vẻ như đó là thiết kế rất nghèo nàn. –

+0

Tôi thật sự đồng ý ... –

7

Lý do lớn nhất để luôn chỉ định các đối tượng miền làm giao diện thay vì trực tiếp như các lớp là cung cấp cho bạn mức độ tự do khi triển khai. Trong ví dụ của bạn, bạn chỉ có một loại IAccount, do đó, nó là một chút redunant.

Nhưng nếu bạn đã có, ví dụ:

public class Account : IAccount { ... }  // Usual account, persistent 
public class MockAccount : IAccount { ... } // Test mock object 
public class TransAccount : IAccount { ... } // Account, not persistent 
public class SimAccount : IAccount { ... } // Account in a performance sim 

và vân vân?

Bằng cách xác định đối tượng tên miền dưới dạng giao diện, bạn có thể thay thế triển khai mà không làm phiền định nghĩa miền của mình.

+0

Xóa câu bắt đầu "Trong ví dụ này ...". Nhưng những gì bạn sẽ làm để thực hiện giao diện chắc chắn là một vị trí của sự thay đổi, và một tài sản mong muốn của một thiết kế OO là phải có "các điểm bản lề" tại vị trí có khả năng thay đổi. BTW, tôi thực sự sử dụng để tranh luận câu hỏi này giống như bạn đang có, và đã được chuyển đổi khi tôi muốn bắt đầu chế nhạo một số công cụ để thử nghiệm. –

+0

+1 điều này có vẻ ngớ ngẩn cho đến khi bạn hai năm duy trì ứng dụng nguyên khối và bạn cần thực hiện thay đổi để hỗ trợ các biến thể mới mà không làm gián đoạn các lớp phụ thuộc. Ngoài ra, TDD là không có trí tuệ. –

+0

Nếu bạn đã biết câu trả lời, tại sao bạn lại đặt câu hỏi? –

5

Nói chung, nếu các lớp học của tôi sẽ không trở thành một phần của mẫu thiết kế như Chiến lược hoặc Khách truy cập, tôi không thêm giao diện.

Thêm giao diện thực sự hữu ích cho các mẫu thiết kế như Chiến lược và Khách truy cập, nhưng trong những trường hợp đó, tôi không sao chép các getters và setters của các lớp miền. Thay vào đó, tôi tạo các giao diện dành riêng cho các giao diện mẫu thiết kế mà tôi tạo ra.

interface SomeStrategy { 
    void doSomething(StrategyData data); 
} 

interface StrategyData { 
    String getProperty1(); 

    String getProperty2(); 
} 

Điều đó cho phép tôi cho phép các lớp miền triển khai các giao diện đó hoặc sử dụng mẫu Bộ điều hợp. Tôi thấy đây là một cách tiếp cận rõ ràng hơn, chỉ tạo giao diện vì lợi ích của nó.

Thiết kế phải luôn giảm độ không đảm bảo. Tạo ra các giao diện vì lợi ích của nó không làm giảm sự không chắc chắn, trên thực tế nó có thể làm tăng sự nhầm lẫn vì nó không có ý nghĩa gì cả.

+0

Câu trả lời hay, thx –

3

One-to-One Giao diện trên thực thể là một mô hình chống

James Gregory đặt nó tốt hơn tôi here.

+0

Câu trả lời hay, cảm ơn vì liên kết! –

+0

Tất nhiên Anemic Domain là vấn đề thực sự. Nhưng đó là khi bạn đã có một. Bạn ít nhất có thể tạo ra một chất cách điện giữa người phụ thuộc và việc triển khai để bạn có thể thay đổi với ít đau đầu hơn. – jeremyjjbrown

0

Tại sao điều này lại bị xáo trộn?

Tôi thấy có giao diện cho đối tượng tên miền, như Charlie Martin cho biết, cho phép tôi chọn triển khai của mình.

Ví dụ cơ bản là định danh (object.Id) cho một đối tượng, điều này sẽ khác nhau tùy thuộc vào nơi bạn lưu trữ đối tượng đó và trách nhiệm tạo đối tượng đó hoặc có thể không nghỉ ngơi trong việc triển khai dữ liệu sau này. Trong SQL Server, bạn có thể đi cho một autonumber, nhưng trong Azure lưu trữ bảng bạn có thể đi cho một Guid, nhưng bạn không muốn phải thay đổi logic kinh doanh của bạn ứng dụng bởi vì bạn thay đổi nơi bạn lưu trữ dữ liệu của bạn.

Tôi có thể hoặc không chọn để đối tượng miền của mình tiếp tục tồn tại hoặc thậm chí sử dụng nó trong lớp trình bày - tùy thuộc vào phạm vi ứng dụng của tôi tốt nhất. Nhưng việc thêm một bộ giao diện miền phổ biến trong một lớp chung cho phép tôi viết các dịch vụ chống lại chúng và tái sử dụng chúng một lần nữa và một lần nữa.

Chúng tôi sẽ đi qua cùng một lập luận về những gì cần được một địa chỉ nếu chúng tôi đã không có IAddress, lập trình mới sẽ được viết lại các công cụ cho thẻ tín dụng nếu nó không cho ICreditCard.

Nhãn chống mẫu là sử dụng ngôn ngữ không tốt, việc đơn giản hóa việc mô tả giá trị của giải pháp cho các tác vụ phức tạp và đa dạng trở nên quá đơn giản.

Có một vị trí cho hầu hết các mẫu thậm chí là Singleton bị chặn, có nghĩa là nó không phải là "chống mẫu", ít nhất là theo như thuật ngữ gợi ý.

+0

Chắc chắn, bạn sẽ cần phải sử dụng generics, không phải giao diện, để trừu tượng sự khác biệt về kiểu cho id đối tượng, trừ khi chính khóa được mô hình hóa trên loại yếu nhất (ví dụ: chuỗi). – StuartLC

+0

Tôi sử dụng một chuỗi mọi lúc, trở nên quá phức tạp nếu bạn sử dụng Generics, bạn phải nói với dịch vụ của bạn về generic trong mô hình của bạn, và nếu nó có một thuộc tính con là một thực thể chung và dịch vụ là generic - bạn có được dift của tôi –

1

Tôi đồng ý với bạn. Giao diện nên hoạt động như một hợp đồng, do đó không có giá trị từ việc có giao diện một-một với các thực thể miền. Nó có thể hữu ích nếu bạn muốn trừu tượng một hành vi nào đó. Nhưng, điều này sẽ làm việc trong một số trường hợp.

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