Dalam banyak hal saya benar-benar menyukai gagasan antarmuka Fluent, tetapi dengan semua fitur modern C # (inisialisasi, lambdas, parameter bernama) Saya mendapati diri saya berpikir, "apakah itu layak?", Dan "Apakah ini pola yang tepat untuk menggunakan?". Adakah yang bisa memberi saya, jika bukan praktik yang diterima, setidaknya pengalaman mereka sendiri atau matriks keputusan tentang kapan harus menggunakan pola Fasih?
Kesimpulan:
Beberapa aturan praktis yang baik dari jawaban sejauh ini:
- Antarmuka yang lancar sangat membantu ketika Anda memiliki lebih banyak tindakan daripada setter, karena panggilan mendapat manfaat lebih banyak dari pass-through konteks.
- Antarmuka yang lancar harus dianggap sebagai lapisan di atas api, bukan satu-satunya cara penggunaan.
- Fitur-fitur modern seperti lambdas, inisialisasi, dan parameter bernama, dapat bekerja bahu-membahu untuk membuat antarmuka yang lancar lebih ramah.
Berikut adalah contoh dari apa yang saya maksudkan dengan fitur-fitur modern yang membuatnya merasa kurang dibutuhkan. Ambil contoh, (mungkin contoh buruk) antarmuka Fasih yang memungkinkan saya untuk membuat Karyawan seperti:
Employees.CreateNew().WithFirstName("Peter")
.WithLastName("Gibbons")
.WithManager()
.WithFirstName("Bill")
.WithLastName("Lumbergh")
.WithTitle("Manager")
.WithDepartment("Y2K");
Dapat dengan mudah ditulis dengan inisialisasi seperti:
Employees.Add(new Employee()
{
FirstName = "Peter",
LastName = "Gibbons",
Manager = new Employee()
{
FirstName = "Bill",
LastName = "Lumbergh",
Title = "Manager",
Department = "Y2K"
}
});
Saya juga bisa menggunakan parameter bernama dalam konstruktor dalam contoh ini.
Jawaban:
Menulis antarmuka yang lancar (saya sudah mencoba - coba itu) membutuhkan lebih banyak usaha, tetapi memang ada hasil karena jika Anda melakukannya dengan benar, maksud dari kode pengguna yang dihasilkan lebih jelas. Ini pada dasarnya merupakan bentuk domain spesifik.
Dengan kata lain, jika kode Anda dibaca lebih banyak daripada yang tertulis (dan kode apa yang tidak?), Maka Anda harus mempertimbangkan membuat antarmuka yang lancar.
Antarmuka yang lancar lebih banyak tentang konteks, dan jauh lebih dari sekedar cara untuk mengkonfigurasi objek. Seperti yang Anda lihat di tautan di atas, saya menggunakan API fasih-ish untuk mencapai:
objectA.
intellisense memberi Anda banyak petunjuk. Dalam kasus saya di atas,plm.Led.
memberi Anda semua opsi untuk mengendalikan LED bawaan, danplm.Network.
memberi Anda hal-hal yang dapat Anda lakukan dengan antarmuka jaringan.plm.Network.X10.
Memberi Anda subset dari tindakan jaringan untuk perangkat X10 Anda tidak akan mendapatkan ini dengan inisialisasi konstruktor (kecuali jika Anda ingin harus membangun objek untuk setiap jenis tindakan yang berbeda, yang tidak idiomatis).Satu hal yang biasanya saya lakukan adalah:
Saya tidak melihat bagaimana Anda dapat melakukan hal seperti itu juga tanpa antarmuka yang lancar.
Sunting 2 : Anda juga dapat membuat peningkatan keterbacaan yang sangat menarik, seperti:
sumber
Scott Hanselman berbicara tentang ini dalam Episode 260 podcastnya Hanselmin dengan Jonathan Carter. Mereka menjelaskan bahwa antarmuka yang lancar lebih mirip UI pada API. Anda seharusnya tidak menyediakan antarmuka yang lancar sebagai satu-satunya titik akses, tetapi sebaliknya menyediakannya sebagai semacam kode-UI di atas "antarmuka API biasa".
Jonathan Carter juga berbicara sedikit tentang desain API di blog-nya .
sumber
Antarmuka yang lancar adalah fitur yang sangat kuat untuk diberikan dalam konteks kode Anda, ketika don dengan alasan "benar".
Jika tujuan Anda adalah membuat rantai kode satu-garis besar-besaran sebagai semacam pseudo-black-box, maka Anda mungkin menggonggong pohon yang salah. Jika di sisi lain Anda menggunakannya untuk menambah nilai ke antarmuka API Anda dengan menyediakan sarana untuk membuat panggilan metode panggilan dan meningkatkan keterbacaan kode, maka dengan banyak perencanaan dan upaya yang baik, saya pikir upaya ini sepadan.
Saya akan menghindari mengikuti apa yang tampaknya menjadi "pola" yang umum ketika membuat antarmuka yang lancar, di mana Anda memberi nama semua metode lancar Anda "dengan" -sesuatu, karena merampas antarmuka API yang berpotensi baik dari konteksnya, dan karena itu nilai intrinsiknya .
Kuncinya adalah memikirkan sintaks yang lancar sebagai implementasi spesifik dari bahasa khusus Domain. Sebagai contoh yang sangat bagus dari apa yang saya bicarakan, lihat StoryQ, yang menggunakan kelancaran sebagai sarana untuk mengekspresikan DSL dengan cara yang sangat berharga dan fleksibel.
sumber
position.withX(5)
versusposition.getDistanceToOrigin()
Catatan awal: Saya mengambil masalah dengan satu asumsi dalam pertanyaan, dan menarik kesimpulan spesifik saya (pada akhir posting ini) dari itu. Karena ini mungkin tidak menghasilkan jawaban yang lengkap dan mencakup, saya menandainya sebagai CW.
Di mata saya, dua versi ini harus berarti dan melakukan hal yang berbeda.
Berbeda dengan versi non-fasih, versi fasih menyembunyikan fakta bahwa yang baru
Employee
jugaAdd
diedit ke koleksiEmployees
- itu hanya menunjukkan bahwa objek baru adalahCreate
d.Arti
….WithX(…)
ambigu, terutama untuk orang yang berasal dari F #, yang memilikiwith
kata kunci untuk ekspresi objek : Mereka mungkin menafsirkanobj.WithX(x)
sebagai objek baru yang berasal dariobj
yang identik denganobj
kecuali untukX
propertinya, yang nilainyax
. Di sisi lain, dengan versi kedua, jelas bahwa tidak ada objek turunan dibuat, dan bahwa semua properti ditentukan untuk objek asli.Ini
….With…
memiliki arti lain: mengalihkan "fokus" inisialisasi properti ke objek yang berbeda. Fakta bahwa API Anda lancar memiliki dua arti berbeda untukWith
membuatnya sulit untuk menafsirkan dengan benar apa yang terjadi ... yang mungkin mengapa Anda menggunakan lekukan dalam contoh Anda untuk menunjukkan makna yang dimaksud dari kode itu. Akan lebih jelas seperti ini:Kesimpulan: "Menyembunyikan" fitur bahasa yang cukup sederhana
new T { X = x }
,, dengan API yang lancar (Ts.CreateNew().WithX(x)
) jelas dapat dilakukan, tetapi:Harus diperhatikan bahwa pembaca kode fasih yang dihasilkan masih mengerti apa tepatnya itu. Artinya, API yang lancar harus transparan dalam arti, dan tidak ambigu. Merancang API semacam itu mungkin lebih banyak pekerjaan daripada yang diperkirakan (mungkin harus diuji untuk kemudahan penggunaan dan penerimaan), dan / atau ...
mendesainnya mungkin lebih banyak pekerjaan daripada yang diperlukan: Dalam contoh ini, API yang lancar menambahkan sangat sedikit "kenyamanan pengguna" di atas API yang mendasarinya (fitur bahasa). Orang bisa mengatakan bahwa API yang lancar harus membuat fitur API / bahasa yang mendasarinya "lebih mudah digunakan"; yaitu, itu harus menghemat banyak usaha programmer. Jika itu hanya cara lain untuk menulis hal yang sama, itu mungkin tidak sepadan, karena itu tidak membuat hidup programmer lebih mudah, tetapi hanya membuat kerja perancang lebih keras (lihat kesimpulan # 1 tepat di atas).
Kedua poin di atas diam-diam menganggap bahwa API lancar adalah lapisan di atas API atau fitur bahasa yang ada. Asumsi ini mungkin merupakan pedoman lain yang baik: API yang lancar dapat menjadi cara ekstra untuk melakukan sesuatu, bukan satu-satunya cara. Artinya, mungkin ide yang baik untuk menawarkan API yang lancar sebagai pilihan "memilih".
sumber
Saya suka gaya fasih, itu mengekspresikan niat sangat jelas. Dengan contoh objek initaliser yang Anda miliki setelah, Anda harus memiliki setter properti publik untuk menggunakan sintaks itu, Anda tidak dengan gaya fasih. Mengatakan itu, dengan contoh Anda, Anda tidak mendapatkan banyak dari setter publik karena Anda hampir pergi untuk metode set / get gaya java-esque.
Yang membawa saya ke poin kedua, saya tidak yakin apakah saya akan menggunakan gaya fasih seperti yang Anda miliki, dengan banyak setter properti, saya mungkin akan menggunakan versi kedua untuk itu, saya merasa lebih baik ketika Anda memiliki banyak kata kerja untuk dirangkai, atau setidaknya banyak melakukan daripada pengaturan.
sumber
Saya tidak terbiasa dengan istilah antarmuka lancar , tetapi mengingatkan saya pada beberapa API yang saya gunakan termasuk LINQ .
Secara pribadi saya tidak melihat bagaimana fitur-fitur modern C # akan mencegah kegunaan dari pendekatan semacam itu. Saya lebih suka mengatakan mereka berjalan beriringan. Misalnya lebih mudah untuk mencapai antarmuka seperti itu dengan menggunakan metode ekstensi .
Mungkin jelaskan jawaban Anda dengan contoh konkret tentang bagaimana antarmuka yang lancar dapat diganti dengan menggunakan salah satu fitur modern yang Anda sebutkan.
sumber