Là sử dụng giao diện cho kiểu dữ liệu là một mô hình chống?


9

Giả sử tôi có một thực thể khác nhau trong mô hình của mình (sử dụng EF), giả sử Người dùng, Sản phẩm, Hóa đơn và Đơn hàng.

Tôi đang viết một điều khiển người dùng có thể in các bản tóm tắt của các đối tượng thực thể trong ứng dụng của tôi trong đó các thực thể thuộc về tập hợp được quyết định trước, trong trường hợp này tôi nói rằng các bản tóm tắt của Người dùng và Sản phẩm có thể được tóm tắt.

Tất cả các bản tóm tắt sẽ chỉ có một ID và một mô tả, vì vậy tôi tạo một giao diện đơn giản cho việc này:

 public interface ISummarizableEntity {     
       public string ID { get; }    
       public string Description { get; } 
 }

Sau đó, đối với các thực thể trong câu hỏi, tôi tạo một lớp một phần thực hiện giao diện này:

public partial class User : ISummarizableEntity
{
    public string ID
    {
        get{ return UserID.ToString(); }
    }

    public string Description 
    {
        get{ return String.Format("{0} {1} is from {2} and is {3} years old", FirstName, LastName, Country, Age); }
    }
}

public partial class Product: ISummarizableEntity
{
    public string ID
    {
        get{ return ProductID.ToString(); }
    }

    public string Description 
    {
        get{ return String.Format("{0} weighs {1}{2} and belongs in the {3} department", ProductName, WeightValue, WeightUnit, Department); }
    }
}

Bằng cách này, quyền kiểm soát người dùng / chế độ xem một phần của tôi chỉ có thể liên kết với bất kỳ bộ sưu tập ISummarizableEntity nào và hoàn toàn không cần quan tâm đến nguồn. Tôi đã được thông báo rằng các giao diện không nên được sử dụng như kiểu dữ liệu nhưng tôi không nhận được nhiều thông tin hơn thế. Theo như tôi có thể thấy, mặc dù các giao diện thường mô tả hành vi, nhưng chỉ sử dụng các thuộc tính không phải là một kiểu chống mẫu vì các thuộc tính chỉ là đường cú pháp cho getters / setters.

Tôi có thể tạo một kiểu dữ liệu cụ thể và ánh xạ từ các thực thể đến đó nhưng tôi không thể thấy được lợi ích. Tôi có thể làm cho các đối tượng thực thể kế thừa từ một lớp trừu tượng và sau đó xác định các thuộc tính nhưng sau đó tôi đang khóa các thực thể không sử dụng nữa vì chúng ta không thể có nhiều kế thừa. Tôi cũng sẵn sàng để có bất kỳ đối tượng nào là ISummarizableEntity nếu tôi muốn (rõ ràng tôi sẽ đổi tên giao diện)

Giải pháp tôi đang sử dụng trong tâm trí của tôi là duy trì, có thể mở rộng, có thể kiểm tra và khá mạnh mẽ. Bạn có thể thấy các mô hình chống ở đây?


Có bất kỳ lý do nào bạn thích điều này hơn là có một cái gì đó như EntitySummary, với UserProductmỗi có một phương pháp như thế public EntitySummary GetSummary()nào?
Ben Aaronson

@Ben, bạn đề nghị một tùy chọn hợp lệ. Nhưng nó vẫn sẽ yêu cầu định nghĩa của một giao diện cho phép người gọi biết rằng họ có thể mong đợi một đối tượng có phương thức GetSummary (). Về cơ bản, đó là cùng một thiết kế với mức độ mô đun được thêm vào khi triển khai. Thậm chí có thể là một ý tưởng tốt nếu bản tóm tắt cần phải sống riêng (tuy nhiên ngắn gọn) tách biệt với nguồn của nó.
Kent A.

@KentAnderson Tôi đồng ý. Nó có thể hoặc không thực sự là một ý tưởng tốt, tùy thuộc vào giao diện tổng thể của các lớp này và cách sử dụng tóm tắt.
Ben Aaronson

Câu trả lời:


17

Giao diện không mô tả hành vi. Hoàn toàn ngược lại, đôi khi.

Các giao diện mô tả các hợp đồng, chẳng hạn như "nếu tôi cung cấp đối tượng này cho bất kỳ phương thức nào chấp nhận ISummarizableEntity, thì đối tượng này phải là một thực thể có thể tự tóm tắt" - trong trường hợp của bạn, được xác định là có thể trả về ID chuỗi và Mô tả chuỗi.

Đó là một cách sử dụng hoàn hảo các giao diện. Không có mô hình chống ở đây.


2
"Giao diện không mô tả hành vi." Làm thế nào là "tóm tắt chính nó" không phải là một hành vi?
Doval

2
@ThomasStringer, thừa kế, từ quan điểm thuần túy OO, ngụ ý tổ tiên chung (ví dụ: hình vuông và hình tròn là cả hai hình dạng ). Trong ví dụ của OP, Người dùng và Sản phẩm chia sẻ không có tổ tiên chung hợp lý. Kế thừa trong trường hợp này sẽ là một mô hình chống rõ ràng.
Kent A.

2
@Doval: Tôi đoán tên của giao diện có thể mô tả hành vi dự kiến. Nhưng nó không phải; giao diện có thể được đặt tên bằng IHasIdAndDes mô tả và câu trả lời sẽ giống nhau. Giao diện tự nó không mô tả hành vi, nó mô tả kỳ vọng.
pdr

2
@pdr Nếu bạn gửi 20V qua giắc cắm tai nghe, điều tồi tệ sẽ xảy ra. Hình dạng là không đủ; có một kỳ vọng rất thực tế và rất quan trọng về loại tín hiệu nào sẽ đi qua phích cắm đó. Đây chính xác là lý do tại sao giả vờ rằng các giao diện không có thông số kỹ thuật hành vi được đính kèm với chúng là sai. Bạn có thể làm gì với Listmột danh sách không hoạt động như một danh sách?
Doval 4/03/2015

3
Một phích cắm điện với giao diện phù hợp có thể vừa với ổ cắm, nhưng điều đó không có nghĩa là nó sẽ dẫn điện (hành vi mong muốn).
JeffO

5

Bạn đã chọn đường dẫn tốt hơn cho thiết kế này bởi vì bạn đang xác định một loại hành vi cụ thể sẽ được yêu cầu của nhiều loại đối tượng, khác nhau. Kế thừa trong trường hợp này sẽ ngụ ý một mối quan hệ phổ biến giữa các lớp không thực sự tồn tại. Trong trường hợp này, khả năng kết hợp được ưa chuộng hơn thừa kế.


3
Giao diện không liên quan gì đến thừa kế.
DougM

1
@DougM, có thể tôi đã không nói tốt, nhưng tôi khá chắc chắn rằng chúng tôi đồng ý.
Kent A.

1

Các giao diện chỉ mang thuộc tính nên tránh vì:

  • nó che giấu ý định: bạn chỉ cần một thùng chứa dữ liệu
  • nó khuyến khích sự kế thừa: xác suất ai đó sẽ trộn lẫn mối quan tâm trong tương lai
  • nó ngăn chặn việc tuần tự hóa

Ở đây bạn đang trộn lẫn hai mối quan tâm:

  • tóm tắt dưới dạng dữ liệu
  • tóm tắt như một hợp đồng

Một bản tóm tắt được tạo thành từ hai chuỗi: id và mô tả. Đây là dữ liệu đơn giản:

public class Summary {
    private readonly string id;
    private readonly string description;
    public Summary(string id, string description) {
        this.id = id;
        this.description = description;
    }
    public string Id { get { return id; } }
    public string Description { get { return description; } }
}

Bây giờ bạn đã xác định tóm tắt là gì bạn muốn xác định hợp đồng:

public interface ISummarizableEntity {
    public Summary GenerateSummary();
}

Lưu ý rằng sử dụng trí thông minh trong getters là một mô hình chống và nên tránh: nó nên được đặt trong các chức năng thay thế. Đây là cách triển khai như sau:

public partial class User : ISummarizableEntity {
    public Summary GenerateSummary() {
        var id = UserID.ToString();
        var description = String.Format("{0} {1} is from {2} and is {3} years old", FirstName, LastName, Country, Age);
        return new Summary(id,description);
    }
}

public partial class Product : ISummarizableEntity {
    public Summary GenerateSummary() {
        var id = ProductID.ToString();
        var description = String.Format("{0} weighs {1}{2} and belongs in the {3} department", ProductName, WeightValue, WeightUnit, Department);
        return new Summary(id,description);
    }
}

"Các giao diện chỉ mang thuộc tính nên tránh" Tôi không đồng ý. Cung cấp lý do tại sao bạn nghĩ như vậy.
Euphoric

Bạn nói đúng, tôi đã thêm một số chi tiết
vanna
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.