Pikiran dan Praktik Terbaik tentang Kelas dan Anggota Statis [ditutup]

11

Saya sangat ingin tahu tentang pemikiran dan praktik terbaik industri mengenai anggota statis, atau seluruh kelas statis. Apakah ada kerugian untuk ini, atau apakah ia berpartisipasi dalam anti-pola?

Saya melihat entitas ini sebagai "kelas utilitas / anggota", dalam arti bahwa mereka tidak memerlukan atau meminta instantiating kelas untuk menyediakan fungsionalitas.

Apa pemikiran umum dan praktik terbaik industri dalam hal ini?

Lihat contoh di bawah ini kelas dan anggota untuk menggambarkan apa yang saya rujuk.

// non-static class with static members
//
public class Class1
{
    // ... other non-static members ...

    public static string GetSomeString()
    {
        // do something
    }
}

// static class
//
public static class Class2
{
    // ... other static members ...

    public static string GetSomeString()
    {
        // do something
    }
}

Terima kasih sebelumnya!

Thomas Stringer
sumber
1
The artikel MSDN pada Kelas Statis dan Metode Statis memberikan pengobatan yang baik cantik.
Robert Harvey
1
@Robert Harvey: Walaupun artikel yang Anda referensikan bermanfaat, artikel ini tidak memberikan banyak manfaat dalam hal praktik terbaik dan seperti apa jebakannya ketika menggunakan kelas statis.
Bernard

Jawaban:

18

Secara umum, hindari statika - terutama segala keadaan statis.

Mengapa?

  1. Statika menyebabkan masalah dengan konkurensi. Karena hanya ada satu contoh, itu secara alami dibagi di antara eksekusi bersamaan. Sumber daya yang dibagikan itu adalah kutukan dari pemrograman bersamaan, dan seringkali tidak perlu dibagikan.

  2. Statika menyebabkan masalah dengan pengujian unit. Kerangka pengujian unit apa pun yang layak adalah pengujian menjalankan garam secara bersamaan. Kemudian Anda mengalami # 1. Lebih buruk lagi, Anda mempersulit pengujian Anda dengan semua hal pengaturan / teardown, dan peretasan yang Anda akan jatuh ke dalam mencoba dan "berbagi" kode pengaturan.

Ada banyak hal kecil juga. Statika cenderung tidak fleksibel. Anda tidak dapat antarmuka mereka, Anda tidak dapat menimpa mereka, Anda tidak dapat mengontrol waktu konstruksi mereka, Anda tidak dapat menggunakannya dengan baik dalam obat generik. Anda tidak dapat benar-benar versi mereka.

Tentu saja ada penggunaan statika: nilai konstan bekerja dengan baik. Metode murni yang tidak muat dalam satu kelas dapat bekerja sangat baik di sini.

Namun secara umum, hindari mereka.

Telastyn
sumber
Saya ingin tahu sejauh mana ketidakmampuan untuk konkurensi yang Anda maksud. Bisakah Anda mengembangkannya? Jika Anda bermaksud bahwa anggota dapat diakses tanpa pemisahan, itu masuk akal. Kasus penggunaan Anda untuk statika adalah apa yang biasanya saya gunakan untuknya: nilai konstan dan metode murni / utilitas. Jika itu yang terbaik dan kasus penggunaan 99% untuk statika, maka itu memberi saya tingkat kenyamanan. Juga +1 untuk jawaban Anda. Informasi hebat.
Thomas Stringer
@ThomasStringer - hanya saja semakin banyak titik kontak antara utas / tugas berarti lebih banyak peluang untuk masalah konkurensi dan / atau lebih banyak kehilangan kinerja yang melakukan sinkronisasi.
Telastyn
Jadi jika satu utas saat ini mengakses anggota statis maka utas lainnya perlu menunggu sampai utas yang dimiliki melepaskan sumber daya?
Thomas Stringer
@ThomasStringer - mungkin, mungkin tidak. Statika (sangat hampir, dalam kebanyakan bahasa) tidak berbeda dari sumber daya bersama lainnya dalam hal ini.
Telastyn
@ThomasStringer: Sayangnya ini sebenarnya lebih buruk dari ini, kecuali jika Anda menandai anggota volatile. Anda tidak mendapatkan jaminan dari model memori tanpa data yang mudah menguap, jadi mengubah variabel dalam satu utas mungkin tidak langsung mencerminkan atau sama sekali.
Phoshi
17

Jika fungsinya "murni" saya tidak melihat masalah. Fungsi murni hanya beroperasi di parameter input, dan memberikan hasil berdasarkan itu. Itu tidak tergantung pada negara global atau konteks eksternal.

Jika saya melihat contoh kode Anda sendiri:

public class Class1
{
    public static string GetSomeString()
    {
        // do something
    }
}

Fungsi ini tidak mengambil parameter apa pun. Jadi, itu mungkin tidak murni (satu-satunya implementasi murni dari fungsi ini adalah mengembalikan konstanta). Saya berasumsi bahwa contoh ini tidak mewakili masalah Anda yang sebenarnya, saya hanya menunjukkan bahwa ini mungkin bukan fungsi murni.

Mari kita ambil contoh berbeda:

public static bool IsOdd(int number) { return (number % 2) == 1; }

Tidak ada yang salah dengan fungsi ini statis. Kami bahkan bisa menjadikan ini sebagai fungsi ekstensi, yang memungkinkan kode klien menjadi lebih mudah dibaca. Fungsi ekstensi yang pada dasarnya hanya jenis khusus dari fungsi statis.

Telastyn dengan benar menyebutkan concurrency sebagai potensi masalah dengan anggota statis. Namun, karena fungsi ini tidak menggunakan status bersama, tidak ada masalah konkurensi di sini. Seribu utas dapat memanggil fungsi ini secara bersamaan tanpa ada masalah konkurensi.

Dalam kerangka NET., Metode ekstensi telah ada selama beberapa waktu. LINQ berisi banyak fungsi ekstensi (mis. Enumerable.Where () , Enumerable.First () , Enumerable.Single () , dll.). Kami tidak melihat ini sebagai buruk, kan?

Pengujian unit sering mendapat manfaat ketika kode menggunakan abstraksi yang dapat diganti, memungkinkan pengujian unit untuk mengganti kode sistem dengan uji ganda. Fungsi statis melarang fleksibilitas ini, tetapi ini terutama penting pada batas-batas lapisan arsitektur, di mana kami ingin mengganti, misalnya, lapisan akses data aktual dengan lapisan akses data palsu .

Namun, ketika menulis tes untuk objek yang berperilaku berbeda, tergantung pada apakah beberapa angka ganjil atau genap, kita tidak benar-benar perlu untuk dapat mengganti IsOdd()fungsi dengan implementasi alternatif. Demikian juga, saya tidak melihat kapan kita perlu memberikan Enumerable.Where()implementasi yang berbeda untuk tujuan pengujian.

Jadi mari kita periksa keterbacaan kode klien untuk fungsi ini:

Opsi a (dengan fungsi yang dinyatakan sebagai metode ekstensi):

public void Execute(int number) {
    if (number.IsOdd())
        // Do something
}

Opsi b:

public void Execute(int number) {
    var helper = new NumberHelper();
    if (helper.IsOdd(number))
        // Do something
}

Fungsi statis (ekstensi) membuat potongan kode pertama jauh lebih mudah dibaca, dan keterbacaan sangat penting, jadi gunakan fungsi statis yang sesuai.

Pete
sumber