Baru-baru ini saya melihat basis kode yang memiliki kelas data yang Address
ditentukan di suatu tempat dan kemudian di tempat yang berbeda:
fun Address.toAnschrift() = let { address ->
Anschrift().apply {
// mapping code here...
}
}
Saya merasa bingung untuk tidak memiliki metode ini pada alamat secara langsung. Apakah ada pola atau praktik terbaik yang ditetapkan saat menggunakan metode ekstensi? Atau apakah buku tentang itu masih harus ditulis?
Perhatikan bahwa terlepas dari sintaksis Kotlin dalam contoh saya, saya tertarik pada praktik terbaik umum karena juga akan berlaku untuk C # atau bahasa lain dengan kemampuan itu.
Jawaban:
Metode penyuluhan tidak menyediakan sesuatu yang tidak bisa dilakukan dengan cara lain. Mereka adalah gula sintaksis untuk membuat pengembangan lebih baik, tanpa memberikan manfaat teknis yang sebenarnya.
Metode penyuluhan relatif baru. Standar dan konvensi biasanya diputuskan oleh pendapat umum (ditambah beberapa pengalaman jangka panjang tentang apa yang akhirnya menjadi ide yang buruk), dan saya tidak berpikir kita pada titik di mana kita dapat menarik garis definitif yang disepakati semua orang.
Namun, saya dapat melihat beberapa argumen, berdasarkan pada hal-hal yang saya dengar dari rekan kerja.
1. Mereka biasanya mengganti metode statis.
Metode ekstensi paling umum didasarkan pada hal-hal yang seharusnya metode statis, bukan metode kelas. Mereka terlihat seperti metode kelas, tetapi sebenarnya tidak.
Metode penyuluhan seharusnya tidak dianggap sebagai alternatif untuk metode kelas; melainkan sebagai cara untuk memberikan tampilan dan nuansa "metodis" yang statis dan sintaksis .
2. Ketika metode yang Anda maksud adalah khusus untuk proyek konsumsi tetapi tidak perpustakaan sumber.
Hanya karena Anda mengembangkan perpustakaan dan konsumen tidak berarti Anda bersedia untuk menempatkan logika di tempat yang cocok.
Sebagai contoh:
PersonDto
kelas yang berasal dariDataLayer
proyek Anda .WebUI
Proyek Anda ingin dapat mengonversi aPersonDto
kePersonViewModel
.Anda tidak dapat (dan tidak ingin) menambahkan metode konversi ini ke
DataLayer
proyek Anda . Karena metode ini termasuk dalamWebUI
proyek, ia harus hidup di dalam proyek itu.Metode ekstensi memungkinkan Anda memiliki metode ini dapat diakses secara global di dalam proyek Anda (dan kemungkinan konsumen proyek Anda), tanpa memerlukan
DataLayer
perpustakaan untuk mengimplementasikannya.3. Jika menurut Anda kelas data hanya boleh berisi data.
Misalnya,
Person
kelas Anda berisi properti untuk seseorang. Tetapi Anda ingin dapat memiliki beberapa metode yang memformat beberapa data:Saya telah melihat banyak rekan kerja yang membenci gagasan mencampur data dan logika di kelas. Saya tidak begitu setuju dengan hal-hal sederhana seperti memformat data, tetapi saya mengakui bahwa dalam contoh di atas, rasanya kotor karena
Person
harus bergantung padaSecurityQuestionAnswers
.Menempatkan metode ini dalam metode ekstensi mencegah pengotoran kelas data yang dinyatakan murni.
Perhatikan bahwa argumen ini adalah salah satu gaya. Ini mirip dengan kelas parsial. Ada sedikit atau tidak ada manfaat teknis untuk melakukannya, tetapi memungkinkan Anda untuk memisahkan kode menjadi beberapa file jika Anda menganggapnya lebih bersih (misalnya jika banyak orang menggunakan kelas tetapi tidak peduli tentang metode kustom tambahan Anda).
4. Metode pembantu
Dalam sebagian besar proyek, saya cenderung berakhir dengan kelas pembantu. Ini adalah kelas statis yang biasanya menyediakan beberapa kumpulan metode untuk pemformatan yang mudah.
Misalnya, satu perusahaan tempat saya bekerja memiliki format datetime tertentu yang ingin mereka gunakan. Daripada harus menempelkan string format ke semua tempat, atau menjadikan string format menjadi variabel global, saya memilih metode ekstensi DateTime:
Apakah itu lebih baik daripada metode pembantu statis normal? Aku pikir begitu. Itu membersihkan sintaks. Dari pada
Saya bisa melakukan:
Ini mirip dengan versi lancar dari sintaks yang sama. Saya lebih menyukainya, meskipun tidak ada manfaat teknis dari memiliki satu di atas yang lain.
Semua argumen ini subyektif. Tak satu pun dari mereka yang membahas kasus yang kalau tidak bisa ditutup.
Tetapi sekali lagi, kami dapat mengambil pernyataan Anda bahwa mereka tidak pernah perlu sampai ekstrem:
Jawaban untuk pertanyaan ini, dan pertanyaan Anda, tetap sama:
Satu tambahan menyebutkan:
sumber
Saya setuju dengan Flater bahwa belum ada cukup waktu untuk konvensi untuk mengkristal, tetapi kami memiliki contoh .NET Framework Class Libraries sendiri. Pertimbangkan bahwa ketika metode LINQ ditambahkan ke .NET, mereka tidak ditambahkan langsung ke
IEnumerable
, tetapi sebagai metode ekstensi.Apa yang bisa kita ambil dari ini? LINQ adalah
A.B().C()
bukanC(B(A))
), danJika Anda memiliki ketiga fitur tersebut, metode ekstensi sangat masuk akal. Bahkan, saya berpendapat bahwa jika satu set metode memiliki fitur # 3 dan salah satu dari dua fitur pertama, Anda harus mempertimbangkan membuat mereka metode ekstensi.
Metode ekstensi:
null
nilai karena metode ekstensi yang dipanggil darinull
nilai hanya menerimanull
sebagai argumen pertama,Metode ekstensi memiliki satu manfaat lagi: mereka masih dapat digunakan sebagai metode statis, dan dapat diteruskan secara langsung sebagai nilai ke fungsi urutan yang lebih tinggi. Jadi, jika
MyMethod
ini merupakan metode ekstensi, alih-alih mengatakanmyList.Select(x => x.MyMethod())
, Anda bisa menggunakannyamyList.Select(MyMethod)
. Saya menemukan itu lebih baik.sumber
Kekuatan pendorong di belakang metode ekstensi adalah kemampuan untuk menambahkan fungsionalitas yang Anda butuhkan untuk semua kelas atau antarmuka dari jenis tertentu terlepas dari apakah mereka disegel atau dalam rakitan lain. Anda dapat melihat bukti ini dengan kode LINQ, menambahkan fungsi ke semua
IEnumerable<T>
objek, apakah itu daftar atau tumpukan, dll. Konsepnya adalah untuk membuktikan fungsi di masa depan sehingga jika Anda membuat sendiri,IEnumerable<T>
Anda dapat secara otomatis menggunakan LINQ dengan itu.Yang mengatakan, ada fitur bahasa yang cukup baru sehingga Anda tidak memiliki pedoman kapan harus menggunakan atau tidak menggunakannya. Namun, mereka mengaktifkan sejumlah hal yang sebelumnya tidak mungkin:
Agar adil, hanya waktu yang akan mengatakan seberapa jauh terlalu jauh, atau pada titik mana metode penyuluhan menjadi penghalang dan bukan anugerah. Seperti disebutkan dalam jawaban lain, tidak ada dalam metode ekstensi yang tidak dapat dilakukan dengan metode statis. Namun, ketika digunakan dengan bijaksana mereka dapat membuat kode lebih mudah dibaca.
Bagaimana dengan sengaja menggunakan metode ekstensi di majelis yang sama?
Saya pikir ada nilai dalam memiliki fungsionalitas inti yang teruji dan dipercaya dengan baik, dan kemudian tidak mengacaukannya sampai Anda benar-benar harus melakukannya. Kode baru yang bergantung padanya, tetapi membutuhkan fungsionalitas semata-mata untuk kepentingan kode baru dapat menggunakan Metode Ekstensi untuk menambahkan fitur apa pun untuk mendukung kode baru. Fungsi-fungsi itu hanya menarik untuk kode baru, dan ruang lingkup metode ekstensi terbatas pada namespace tempat mereka dideklarasikan di dalamnya.
Saya tidak akan secara membabi buta mengesampingkan penggunaan metode ekstensi, tetapi saya akan mempertimbangkan apakah fungsionalitas baru harus benar-benar ditambahkan ke kode inti yang ada yang diuji dengan baik.
sumber
Salah satu alasan paling umum untuk menggunakan metode ekstensi adalah sebagai sarana untuk "memperluas, tidak memodifikasi" antarmuka. Daripada memiliki
IFoo
danIFoo2
, di mana yang terakhir memperkenalkan metode baruBar
,Bar
ditambahkan keIFoo
melalui metode ekstensi.Salah satu alasan Linq menggunakan metode ekstensi untuk
Where
,Select
dll adalah untuk memungkinkan pengguna untuk menentukan versi mereka sendiri dari metode ini, yang kemudian digunakan oleh sintaks permintaan Linq juga.Di luar itu, Pendekatan yang saya gunakan, yang tampaknya sesuai dengan apa yang biasanya saya lihat dalam .NET framework setidaknya adalah:
Jadi jika saya memiliki
Option<T>
, saya akan menempatkan hal-hal sepertiHasValue
,Value
,==
, dll dalam jenis itu sendiri. Tapi sesuatu sepertiMap
fungsi, yang mengubah monad dariT1
menjadiT2
, saya memasukkan metode ekstensi:sumber
One of the reasons Linq uses extension methods for Where, Select etc is in order to allow users to define their own versions of these methods, which are then used by the Linq query syntax too.
-- Apa kamu yakin akan hal itu? Sintaks Linq banyak menggunakan ekspresi lambda (yaitu fungsi kelas satu), sehingga tidak perlu menulis versiSelect
danWhere
. Saya tahu tidak ada kasus di mana orang memutar versi mereka sendiri dari fungsi-fungsi ini.if (!predicate(item))
kode ituif (predicate(item))
, hasilnya berubah karena menggunakan versi sayaWhere
.