Apakah menggunakan antarmuka untuk tipe data merupakan anti-pola?

9

Misalkan saya memiliki berbagai entitas dalam model saya (menggunakan EF), katakanlah Pengguna, Produk, Faktur dan Pesanan.

Saya menulis kontrol pengguna yang dapat mencetak ringkasan objek entitas dalam aplikasi saya di mana entitas milik set yang ditentukan sebelumnya, dalam hal ini saya mengatakan bahwa ringkasan Pengguna dan Produk dapat diringkas.

Ringkasan semua hanya memiliki ID dan deskripsi, jadi saya membuat antarmuka sederhana untuk ini:

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

Kemudian untuk entitas yang dimaksud, saya membuat kelas parsial yang mengimplementasikan antarmuka ini:

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); }
    }
}

Dengan cara ini kontrol pengguna saya / tampilan parsial hanya dapat mengikat koleksi ISummarizableEntity dan tidak perlu tertarik pada sumber sama sekali. Saya telah diberitahu bahwa antarmuka tidak boleh digunakan sebagai tipe data tetapi saya tidak mendapatkan informasi lebih dari itu. Sejauh yang saya bisa lihat, meskipun antarmuka biasanya menggambarkan perilaku, hanya menggunakan properti bukan merupakan anti-pola itu sendiri karena properti hanyalah gula sintaksis untuk getter / setter.

Saya bisa membuat tipe data dan peta konkret dari entitas untuk itu tetapi saya tidak bisa melihat manfaatnya. Saya bisa membuat objek entitas mewarisi dari kelas abstrak dan kemudian mendefinisikan properti tetapi kemudian saya mengunci entitas untuk tidak digunakan lebih lanjut karena kita tidak dapat memiliki banyak pewarisan. Saya juga terbuka untuk memiliki objek yang ISummarizableEntity jika saya mau (jelas saya akan mengganti nama antarmuka)

Solusi yang saya gunakan dalam pikiran saya dapat dipertahankan, dapat dikembangkan, diuji dan cukup kuat. Bisakah Anda melihat anti-pola di sini?

Dosa
sumber
Apakah ada alasan Anda lebih suka ini daripada memiliki sesuatu seperti EntitySummary, dengan Userdan Productmasing-masing memiliki metode seperti public EntitySummary GetSummary()?
Ben Aaronson
@ Ben, Anda menyarankan opsi yang valid. Tetapi masih membutuhkan definisi antarmuka yang memungkinkan pemanggil tahu bahwa mereka dapat mengharapkan objek memiliki metode GetSummary (). Ini pada dasarnya desain yang sama dengan tambahan tingkat modularitas dalam implementasi. Mungkin bahkan ide yang baik jika ringkasan perlu hidup sendiri (namun singkat) terpisah dari sumbernya.
Kent A.
@ KentAnderson saya setuju. Ini mungkin atau mungkin bukan ide yang baik, tergantung pada keseluruhan antarmuka kelas-kelas ini dan bagaimana ringkasan digunakan.
Ben Aaronson

Jawaban:

17

Antarmuka tidak menggambarkan perilaku. Justru sebaliknya, kadang-kadang.

Antarmuka menggambarkan kontrak, seperti "jika saya menawarkan objek ini ke metode apa pun yang menerima ISummarizableEntity, objek ini harus berupa entitas yang dapat meringkas sendiri" - dalam kasus Anda, yang didefinisikan sebagai mampu mengembalikan suatu ID string dan Deskripsi string.

Itu penggunaan antarmuka yang sempurna. Tidak ada anti-pola di sini.

pdr
sumber
2
"Antarmuka tidak menggambarkan perilaku." Bagaimana "merangkum dirinya" bukan perilaku?
Doval
2
@ThomasStringer, pewarisan, dari pandangan puritan OO, menyiratkan nenek moyang yang sama (misalnya, kotak dan lingkaran adalah keduanya bentuk ). Dalam contoh OP, Pengguna dan Produk tidak memiliki keturunan yang wajar. Warisan dalam hal ini akan menjadi anti-pola yang jelas.
Kent A.
2
@Doval: Saya kira nama antarmuka dapat menggambarkan perilaku yang diharapkan. Tetapi tidak harus; antarmuka bisa sama-sama dinamai IHasIdAndDescription dan jawabannya akan sama. Antarmuka itu sendiri tidak menggambarkan perilaku, itu menggambarkan harapan.
pdr
2
@ pdr Jika Anda mengirim 20V melalui jack headphone, hal-hal buruk akan terjadi. Bentuknya tidak cukup; ada harapan yang sangat nyata dan sangat penting dari sinyal apa yang akan datang melalui steker itu. Inilah sebabnya mengapa berpura-pura bahwa antarmuka tidak memiliki spesifikasi perilaku yang melekat padanya salah. Apa yang dapat Anda lakukan dengan Listyang tidak berperilaku seperti daftar?
Doval
3
Steker listrik dengan antarmuka yang sesuai mungkin masuk ke outlet, tetapi itu tidak berarti itu akan menghantarkan listrik (perilaku yang diinginkan).
JeffO
5

Anda telah memilih jalur yang lebih baik untuk desain ini karena Anda mendefinisikan tipe perilaku tertentu yang akan diperlukan dari beberapa jenis objek yang berbeda. Warisan dalam hal ini akan menyiratkan hubungan yang sama antara kelas-kelas yang sebenarnya tidak ada. Dalam hal ini, kompabilitas lebih disukai daripada warisan.

Kent A.
sumber
3
Antarmuka tidak ada hubungannya dengan warisan.
DougM
1
@DougM, mungkin saya tidak mengatakannya dengan baik, tapi saya cukup yakin kami setuju.
Kent A.
1

Antarmuka yang hanya membawa properti harus dihindari karena:

  • itu mengaburkan niat: Anda semata-mata membutuhkan wadah data
  • itu mendorong warisan: probabilitas bahwa seseorang akan mencampur kekhawatiran di masa depan
  • itu mencegah serialisasi

Di sini Anda mencampur dua masalah:

  • ringkasan sebagai data
  • ringkasan sebagai kontrak

Ringkasan dibuat dari dua string: id dan deskripsi. Ini data biasa:

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; } }
}

Sekarang setelah Anda menentukan ringkasan apa yang ingin Anda tetapkan kontrak:

public interface ISummarizableEntity {
    public Summary GenerateSummary();
}

Perhatikan bahwa menggunakan intelijen dalam getter adalah anti-pola dan harus dihindari: itu harus ditempatkan dalam fungsi. Berikut ini tampilan implementasi:

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);
    }
}
vanna
sumber
"Antarmuka yang hanya membawa properti harus dihindari" Saya tidak setuju. Berikan alasan mengapa menurut Anda begitu.
Euforia
Anda benar, saya menambahkan beberapa detail
vanna