Mengapa dan kapan saya harus membuat kelas 'statis'? Apa tujuan kata kunci 'statis' di kelas?

47

Kata statickunci pada anggota dalam banyak bahasa berarti Anda tidak boleh membuat turunan dari kelas itu untuk dapat memiliki akses ke anggota itu. Namun, saya tidak melihat adanya pembenaran untuk membuat seluruh kelas static. Mengapa dan kapan saya harus membuat kelas static?

Apa manfaat yang saya dapatkan dari membuat kelas static? Maksud saya, setelah mendeklarasikan kelas statis, kita harus tetap mendeklarasikan semua anggota yang dia ingin akses tanpa instantiasi, sebagai statis juga.

Ini berarti bahwa misalnya, Mathkelas dapat dinyatakan normal (tidak statis), tanpa mempengaruhi cara pengembang kode. Dengan kata lain, membuat kelas statis atau normal agak transparan bagi pengembang.

Saeed Neamati
sumber
Jika Anda mengode dalam gaya Func Prog ala Rich Hickey, ini bisa berguna.
Pekerjaan
1
Menurut pendapat saya, kelas statis hanyalah penopang yang digunakan C # untuk menyembunyikan cacat desain besar dalam bahasa. Mengapa menyusun bahasa di sekitar ideologi segalanya yang tidak masuk akal ini, hanya untuk kemudian memperkenalkan sintaks tambahan sehingga Anda dapat menipu dan mengatasi batasan yang tidak perlu ini. Jika C # baru saja mengizinkan fungsi-fungsi gratis dari awal, tidak perlu kelas statis.
antred

Jawaban:

32

Itu membuat jelas bagi pengguna bagaimana kelas digunakan. Misalnya, akan menjadi omong kosong untuk menulis kode berikut:

Math m = new Math();

C # tidak harus melarang ini tetapi karena tidak ada gunanya, mungkin juga memberitahu pengguna itu. Orang-orang tertentu (termasuk saya) mematuhi filosofi bahwa bahasa pemrograman (dan API ...) harus seketat mungkin untuk membuat mereka sulit digunakan salah: satu-satunya operasi yang diizinkan adalah mereka yang bermakna dan (mudah-mudahan) benar.

Konrad Rudolph
sumber
3
Saya tidak setuju dengan filosofi itu. Masalah yang saya miliki adalah yang perlu diubah. Jadi sementara mungkin masuk akal untuk membatasi sebelum sekarang bahwa pembatasan menghambat pengembangan kita untuk kebutuhan masa depan. Dan pustaka lawas yang terpaksa kami gunakan untuk berinteraksi dengan sistem lama (Yang Anda tulis dan tempel dan staticed semua kelas) tidak menyediakan cara bagi kami untuk memperluas atau memodifikasi kode yang Anda tulis. Hanya karena Anda tidak punya alasan untuk membuat instance kelas Anda tidak berarti bahwa saya tidak akan membutuhkannya di masa depan. Sementara membuat statis suatu kelas utilitas masuk akal, pertimbangkan juga masa depan.
SoylentGray
19
@Chad Kemudian perpustakaan dirancang dengan buruk. Memperluas kelas yang tidak dirancang untuk ekstensi pada akhirnya tidak berhasil, jadi terbaik buat kelas sealeddi tempat pertama. Saya mengakui bahwa tidak semua orang setuju dengan sentimen ini tetapi komentarnya bukan tempat yang baik untuk membahas hal ini. Tetapi dalam kasus staticmasalah ini bahkan tidak berpose: Instansiasi tidakSystem.Math akan pernah masuk akal.
Konrad Rudolph
1
@Konard, jika Anda mendeklarasikan semua anggota Mathkelas sebagai statis tanpa menyatakan Mathkelas sebagai statis, Anda masih dapat menggunakannya, tanpa perlu instantiasi.
Saeed Neamati
11
@ Saeed - Ini benar, tetapi Anda juga bisa membuat instance kelas, yang tidak melayani tujuan apa pun. Apa yang harus saya lakukan dengan turunan kelas Matematika? Untuk secara eksplisit menunjukkan maksud dari kelas (tidak diperlukan atau diinginkan instantiasi), itu ditandai static.
Corbin Maret
3
@ Saeed Mari kita balikkan ini: Saya sarankan Anda membaca jawaban saya lagi karena Anda tampaknya telah salah paham: Komentar Anda tidak terkait dengan jawaban saya. Saya tidak pernah mengatakan bahwa Anda perlu menulis new Math().
Konrad Rudolph
24

StackOverflow memiliki diskusi hebat tentang topik ini . Untuk memudahkan referensi, saya akan menyalin dan menempelkannya di sini, atas nama penulisnya, Mark S. Rasmussen :

Saya menulis pemikiran saya tentang kelas statis di utas sebelumnya :

Saya dulu suka kelas utilitas diisi dengan metode statis. Mereka melakukan konsolidasi besar metode penolong yang seharusnya bisa menyebabkan redundansi dan pemeliharaan. Mereka sangat mudah digunakan, tidak ada instantiation, tidak ada pembuangan, hanya api 'jangan lupa. Saya kira ini adalah usaha tanpa disadari pertama saya dalam menciptakan arsitektur berorientasi layanan - banyak layanan tanpa kewarganegaraan yang baru saja melakukan pekerjaan mereka dan tidak ada yang lain. Namun ketika sistem tumbuh, naga akan datang.

Polimorfisme

Katakanlah kita memiliki metode UtilityClass.SomeMethod yang dengan senang hati berdengung. Tiba-tiba kita perlu sedikit mengubah fungsionalitas. Sebagian besar fungsinya sama, tetapi kami harus mengubah beberapa bagian. Seandainya itu bukan metode statis, kita bisa membuat kelas turunan dan mengubah konten metode sesuai kebutuhan. Karena ini adalah metode statis, kita tidak bisa. Tentu, jika kita hanya perlu menambahkan fungsionalitas sebelum atau setelah metode yang lama, kita dapat membuat kelas baru dan memanggil yang lama di dalamnya - tetapi itu hanya kotor.

Kesengsaraan antarmuka

Metode statis tidak dapat didefinisikan melalui antarmuka karena alasan logika. Dan karena kita tidak bisa mengesampingkan metode statis, kelas statis tidak berguna ketika kita perlu menyebarkannya melalui antarmuka mereka. Ini membuat kami tidak dapat menggunakan kelas statis sebagai bagian dari pola strategi. Kami mungkin memperbaiki beberapa masalah dengan mengirimkan delegasi alih-alih antarmuka.

Pengujian

Ini pada dasarnya berjalan seiring dengan kesengsaraan antarmuka yang disebutkan di atas. Karena kemampuan kami untuk menukar implementasi sangat terbatas, kami juga akan kesulitan mengganti kode produksi dengan kode uji. Sekali lagi, kita dapat membungkusnya tetapi akan mengharuskan kita untuk mengubah sebagian besar kode kita hanya untuk dapat menerima pembungkus, bukan objek yang sebenarnya.

Menumbuhkan gumpalan

Karena metode statis biasanya digunakan sebagai metode utilitas dan metode utilitas biasanya akan memiliki tujuan yang berbeda, kita akan segera berakhir dengan kelas besar yang diisi dengan fungsionalitas yang tidak koheren - idealnya, setiap kelas harus memiliki tujuan tunggal dalam sistem. Saya lebih suka memiliki lima kali kelas selama tujuan mereka didefinisikan dengan baik.

Parameter creep

Pertama-tama, metode statis kecil yang lucu dan polos itu mungkin mengambil satu parameter. Ketika fungsionalitas tumbuh, beberapa parameter baru ditambahkan. Segera parameter lebih lanjut ditambahkan yang bersifat opsional, jadi kami membuat kelebihan metode (atau hanya menambahkan nilai default, dalam bahasa yang mendukungnya). Tak lama, kami memiliki metode yang mengambil 10 parameter. Hanya tiga yang pertama yang benar-benar diperlukan, parameter 4-7 adalah opsional. Tetapi jika parameter 6 ditentukan, 7-9 harus diisi juga ... Seandainya kita membuat kelas dengan tujuan tunggal melakukan apa yang dilakukan metode statis ini, kita bisa menyelesaikannya dengan mengambil parameter yang diperlukan di konstruktor, dan memungkinkan pengguna untuk menetapkan nilai opsional melalui properti, atau metode untuk mengatur beberapa nilai yang saling tergantung pada saat yang sama. Juga,

Menuntut konsumen untuk membuat instance kelas tanpa alasan

Salah satu argumen yang paling umum adalah, mengapa menuntut agar konsumen kelas kami membuat contoh untuk menggunakan metode tunggal ini, sementara setelah itu tidak menggunakan contoh tersebut? Membuat instance kelas adalah operasi yang sangat sangat murah di sebagian besar bahasa, jadi kecepatan bukanlah masalah. Menambahkan baris kode tambahan ke konsumen adalah biaya rendah untuk meletakkan fondasi solusi yang jauh lebih dapat dipertahankan di masa depan. Dan akhirnya, jika Anda ingin menghindari membuat instance, cukup buat pembungkus tunggal kelas Anda yang memungkinkan untuk digunakan kembali dengan mudah - meskipun ini membuat persyaratan bahwa kelas Anda adalah stateless. Jika tidak stateless, Anda masih bisa membuat metode pembungkus statis yang menangani semuanya, sambil tetap memberi Anda semua manfaat dalam jangka panjang. Akhirnya,

Hanya Sith yang membahas absolut

Tentu saja, ada pengecualian untuk ketidaksukaan saya terhadap metode statis. Kelas utilitas sejati yang tidak menimbulkan risiko kembung adalah kasus yang sangat baik untuk metode statis - System.Convert sebagai contoh. Jika proyek Anda hanya sekali saja tanpa persyaratan untuk pemeliharaan di masa depan, arsitektur keseluruhan benar-benar tidak terlalu penting - statis atau non statis, tidak terlalu penting - kecepatan pengembangan memang demikian.

Standar, standar, standar!

Menggunakan metode instan tidak menghambat Anda untuk juga menggunakan metode statis, dan sebaliknya. Selama ada alasan di balik diferensiasi dan itu standar. Tidak ada yang lebih buruk daripada melihat lapisan bisnis yang luas dengan metode implementasi yang berbeda.

Rick
sumber
12
Hmmm, tidak tahu bahwa saya akan menyalin dan menempelkan seluruh jawaban di sini. Mungkin tautan dan parafrase, sertakan sudut pandang alternatif karena Anda menyebutkan "diskusi", berbagi pengalaman Anda sendiri?
Corbin Maret
2
"Only a Sith berurusan dengan absolut" - Aku belum pernah melihat yang digunakan seperti itu sebelumnya .... tapi itu SEMPURNA. Membuatku tertawa.
Brook
4
@Corbin: Mark punya jawaban yang bagus. Saya memberinya kredit dan saya salin / tempel untuk kemudahan referensi. Pandangan saya sendiri tentang hal ini cocok dengan milik Markus. Saya tidak melihat inti dari komentar Anda, selain memulai debat.
Rick
1
@ Rick: Jawaban yang disalin cukup panjang, dan parafrase pasti akan membantu. Hanya kalimat seperti "Ini bukan hanya karena mereka tidak benar-benar berguna, mereka bahkan dapat membahayakan, seperti yang ditunjukkan oleh pos SO ini:" akan membiarkan saya dengan cepat melewatkannya karena saya melihat itu bukan informasi yang saya cari.
blubb
@Simon: LOL SAYA 1+ posting Anda. Dalam upaya untuk berhenti berdebat tentang sesuatu yang begitu bodoh, saya hanya akan setuju. :) Semoga poster asli saya menemukan balasan / salin dan tempel berguna.
Rick
16

Saya terkejut tidak ada orang lain yang menyebutkan bahwa statickelas mengizinkan metode ekstensi - dengan aman memperluas tipe yang ada (termasuk menambahkan definisi metode ke antarmuka ) yang bukan milik Anda. Misalnya, apa yang ada di Scala

trait MyFoo {
  def foo: Int
  def plusFoo(a: Int) = foo + a
}

dapat dinyatakan dalam C # as

public interface IMyFoo {
  int Foo();
}

public static class MyFooExtensions {
  public static int PlusFoo(this IMyFoo f, int a) {
    return f.Foo() + a;
  }
}
Frank Shearar
sumber
Anda menemukan jarum di tumpukan jerami. +1
Saeed Neamati
3

Bagi saya, kelas statis (dalam C #) adalah jenis seperti memanggil suatu fungsi.

Sebagai contoh

public static string DoSomething(string DoSomethingWithThisString){}

Saya melewatkan sebuah string dan mendapatkan kembali string. Semuanya terkandung dalam metode itu. Tidak ada akses ke variabel anggota, dll.

Jujur saja, sebagian besar penggunaannya bagi saya adalah untuk mengurangi baris kode:

Kenapa:

MyClass class = new MyClass();
String s = class.DoSomething("test");

Kapan saya bisa melakukan ini:

String s = MyClass.DoSomething("test");

Jadi, saya akan menggunakan kelas statis dalam kasus-kasus itu, ketika saya ingin melakukan sesuatu tanpa perlu kelas dan berarti lebih sedikit mengetik.

Poin Mark S. valid, tetapi bagi saya jika saya memiliki beberapa metode utilitas lebih mudah untuk berpura-pura saya memanggil fungsi untuk merujuknya sebagai satu baris.

Itu mungkin sederhana, tapi itulah yang saya gunakan static.

Jon Raynor
sumber
1
MyClass baru (). DoSomething ("test") masih valid. Saya sering menggunakan ini untuk Pembuat Data Uji.
JoanComasFdz