Jangan Gunakan "Static" di C #?


109

Saya mengirimkan aplikasi yang saya tulis ke beberapa arsitek lain untuk tinjauan kode. Salah satu dari mereka segera membalas saya dan berkata "Jangan gunakan" statis ". Anda tidak dapat menulis tes otomatis dengan kelas dan metode statis." Statis "harus dihindari."

Saya memeriksa dan sepenuhnya 1/4 kelas saya ditandai "statis". Saya menggunakan statis ketika saya tidak akan membuat turunan kelas karena kelas tersebut adalah kelas global tunggal yang digunakan di seluruh kode.

Dia kemudian menyebutkan sesuatu yang melibatkan teknik mengejek, IOC / DI yang tidak dapat digunakan dengan kode statis. Dia mengatakan sangat disayangkan ketika perpustakaan pihak ke-3 bersifat statis karena tidak dapat diuji.

Apakah arsitek lain ini benar?

pembaruan: berikut adalah contohnya:

APIManager - kelas ini menyimpan kamus API pihak ke-3 yang saya panggil bersamaan dengan waktu yang diizinkan berikutnya. Ini memberlakukan batas penggunaan API yang dimiliki banyak pihak ke-3 dalam persyaratan layanan mereka. Saya menggunakannya di mana saja saya memanggil layanan pihak ke-3 dengan menelepon Thread.Sleep (APIManager.GetWait ("ProviderXYZ")); sebelum melakukan panggilan. Semua yang ada di sini aman untuk thread dan berfungsi baik dengan TPL di C #.


37
staticbaik-baik saja; static ladang perlu diperlakukan dengan sangat hati
Marc Gravell

2
Mengapa dia menulis tes untuk perpustakaan pihak ke-3? Bukankah Anda biasanya hanya menguji kode Anda sendiri dengan asumsi pencipta perpustakaan pihak ke-3 telah melakukan pengujian mereka?
Tidak

3
Keberatan itu agak terlalu umum bagi saya. Dalam kebanyakan kasus Anda tidak akan me-mocj kelas statis, Anda akan mengejek argumen. Bidang statis di mana itu adalah kelas agregat yang perlu diejek, lalu ya.

8
Jelas kolega Anda memiliki kondisi serius - OOPus erythematosus sistemik akut. Mereka membutuhkan pengobatan secepatnya!
SK-logic

6
Ada bagian jawaban untuk memberikan jawaban, saya tidak mengerti mengapa orang berkomentar dalam upaya memberikan seseorang jawaban / saran ... Mengalahkan tujuan dari StackExchange, pasti komentar akan meminta informasi lebih lanjut.
peteski

Jawaban:


121

Itu tergantung pada apakah kelas statis mempertahankan status atau tidak. Secara pribadi, saya tidak punya masalah dengan fungsi stateless yang disatukan dalam kelas statis.


111
Benar. Fungsi statis yang tidak memiliki efek samping adalah fungsi yang paling dapat diuji dari semua.
Robert Harvey

9
Memberi +1 pada itu, tetapi dengan klausa keselamatan: Hampir setiap algoritma abstrak tidak memiliki kewarganegaraan, tetapi itu tidak berarti Anda harus mengimplementasikannya sebagai kelas atau metode statis stateless. Menerapkannya dengan cara seperti itu menyebabkan semua kode yang digunakan hampir tidak terhubung ke sana. Ini berarti misalnya bahwa jika Anda menerapkan algoritma pengurutan sebagai metode statis dan kemudian menggunakannya melalui proyek - bahwa Anda tidak dapat sementara mengganti pengurutan ke algoritma lain yaitu untuk tujuan pengujian dan untuk mempersempit area masalah. Ini merupakan hambatan besar dalam banyak kasus. Selain itu, statis sama sekali OK jika digunakan secara wajar.

11
Singkatnya: mereka adalah fungsi yang paling dapat diuji, tetapi tidak perlu mereka membuat kode lain lebih dapat diuji! Mungkin inilah yang dimaksud arsitek.

4
@ tereško: Bahasa C # memerlukan metode statis untuk menjadi bagian dari kelas statis, jika Anda tidak ingin harus membuat turunan dari kelas untuk memanggil metode. Mungkin maksud Anda "contoh," dan bukan "kelas."
Robert Harvey

8
@quetzalcoatl: Sangat sah untuk meloloskan seorang delegasi (yaitu algoritma yang berbeda) ke metode statis; metode ekstensi di Linq adalah semua metode statis. Contoh: msdn.microsoft.com/en-us/library/…
Robert Harvey

93

Dia terlalu umum tentang itu. Dia benar, itu menghambat pengujian. Namun, statickelas dan metode memiliki tempat mereka dan itu benar-benar tergantung pada konteksnya. Tanpa contoh kode Anda tidak bisa mengatakannya.

Saya menggunakan statis ketika saya tidak akan membuat turunan kelas karena kelas tersebut adalah kelas global tunggal yang digunakan di seluruh kode.

Ini bisa menjadi bau kode yang parah. Untuk apa Anda menggunakan kelas? Untuk menyimpan data? Untuk mengakses database? Lalu dia benar. Anda harus melihat ke injeksi ketergantungan dalam kasus itu, karena kelas statis seperti itu secara efektif adalah singleton implisit.

Jika Anda menggunakannya untuk metode ekstensi atau bantuan yang tidak mengubah status dan hanya beroperasi pada parameter yang Anda berikan, itu biasanya baik-baik saja.


3
1 untuk menyebutkan bahwa pernyataan itu untuk umum dan menyebutkan metode ekstensi, yang juga dapat diuji dan dependensi masih dapat diejek sejauh yang saya tahu.
Tidak

4
Aye statis sebagai contoh kelas tunggal sebagai singleton implisit, itu akan menjadi berantakan ....

"Untuk mengakses database?" kenapa tidak ? jika adaptor tabel tidak statis kemudian membuat kelas statis @ dataset sangat diketik, tidak ada yang salah dengan itu .... kecuali Anda membuktikan maksud Anda dengan referensi atau contoh?
Matematika

27

Saya memeriksa dan sepenuhnya 1/4 kelas saya ditandai "statis". Saya menggunakan statis ketika saya tidak akan membuat turunan kelas karena kelas tersebut adalah kelas global tunggal yang digunakan di seluruh kode.

Hal terbaik untuk dilakukan adalah mencoba dan menguji unit kode Anda. Cobalah merancang tes yang dapat diulang, independen, sederhana, dan uji hanya satu metode pada satu waktu. Coba jalankan tes Anda dalam urutan acak yang berbeda. Bisakah Anda mendapatkan bangunan "hijau" yang stabil?

Jika ya, itu poin yang valid untuk mempertahankan kode Anda. Namun, jika Anda mengalami kesulitan, maka mungkin Anda harus menggunakan metode berbasis contoh.


7
Ini adalah titik yang menurut saya juga. Beberapa kelas gaya 'helper' statis dan stateless baik-baik saja, tetapi jika Anda memiliki 25% penuh dari semua kelas Anda sebagai statis, tidak mungkin usaha Anda terbatas pada kasus itu.
Matthew Scharley

2
@ MatthewScharley - dia mungkin mendapat 4 kelas, dan 1 dari mereka adalah Statis :)
Alexus

1
Perhatikan bahwa jika Anda menggunakan stibcs seperti (seperti lajang), yang kemudian menciptakan lebih banyak contoh mungkin merupakan pekerjaan yang sulit. Seperti misalnya membuat aplikasi yang menangani dokumen, Anda akan mengalami masalah saat Anda ingin mengelola banyak dokumen.
Michel Keijzers

11

Jawaban yang sudah diposting mencakup banyak poin yang sangat bagus, tetapi ada satu yang sepertinya tidak ada:

Ladang statis tidak pernah mengumpulkan sampah.

Ini sangat penting jika Anda memiliki aplikasi dengan banyak kendala memori, dan pola ini bisa sangat umum ketika orang mencoba menerapkan cache.

Fungsi statis tidak seburuk itu, tetapi semua orang sudah membahas ini dengan cukup detail.


10

Salah satu keuntungan yang Anda dapatkan dari IoC / DI adalah bahwa sebagian besar interaksi antar kelas dinegosiasikan antar antarmuka. Ini membuat pengujian unit mudah karena antarmuka dapat diejek secara otomatis atau semi-otomatis, dan karenanya masing-masing bagian dapat diuji untuk input dan output. Selain itu, di luar testabilty, menempatkan antarmuka di antara segalanya memungkinkan Anda untuk memiliki kode yang paling modular - Anda dapat dengan mudah mengganti satu implementasi tanpa begitu banyak khawatir bahwa Anda mengacaukan dependensi.

Karena C # tidak memiliki metaclasses, kelas tidak dapat mengimplementasikan antarmuka menggunakan fitur statis, sehingga fitur statis kelas akhirnya mengacaukan segala upaya untuk menerapkan model objek IoC / DI murni. Artinya, Anda tidak dapat membuat tiruan untuk mengujinya, dan Anda harus membuat dependensi nyata.

Jika perusahaan / proyek Anda banyak berinvestasi dalam melakukan IoC, ini tentu saja merupakan keprihatinan yang masuk akal, dan rasa sakit yang Anda alami adalah untuk keuntungan semua. Dari sudut pandang arsitektur, bagaimanapun, saya pribadi tidak berpikir bahwa model apa pun harus diikuti sampai ke liang kubur. Ada beberapa hal yang masuk akal untuk diimplementasikan menggunakan metode statis - strategi desain tunggal, misalnya. Saya sendiri kurang cenderung ke kelas statis karena saya pikir mereka cenderung mulai kehilangan keunggulan OO, tetapi ada kalanya kelas perpustakaan mungkin ekspresi yang lebih alami dari sesuatu daripada mesin.


Commenter mengingatkan saya pada metode ekstensi, yang tentu saja harus di kelas statis di C #. Itu sah, dan merupakan contoh bagaimana IoC murni tidak bekerja dengan sangat baik di C #, setidaknya jika Anda mencoba memanfaatkan luasnya bahasa.


1
Jika suatu kelas dibuat statis untuk alasan yang benar dan diimplementasikan dengan benar seperti misalnya metode ekstensi mereka masih sangat dapat diuji karena mereka tidak memiliki dependensi eksternal dan mandiri dan dengan demikian tidak perlu mengejek. Haruskah kebutuhan antarmuka tidak didorong oleh persyaratan desain untuk memenuhi persyaratan bisnis terbaik bukan demi menjaga proyek IoC / DI murni?
Tidak

1
Anda dan saya sepakat pada poin umum bahwa Anda harus memilih alat yang tepat untuk pekerjaan yang tepat dan tidak diborgol oleh filosofi. Namun, jika ada budaya yang sudah mapan dalam proyek IoC / DI murni Anda, itu akan sama menyakitkannya dengan mengubah solusi top-down tradisional menjadi IoC / DI. Rekayasa perlu mempertimbangkan biaya transisi. Ngomong-ngomong, saya tidak berpikir metode ekstensi cukup membuat Anda di sana. Saya pikir solusi yang lebih baik untuk perilaku IoCish dengan kelas statis adalah memiliki beberapa kelas yang dipilih antara pada waktu kompilasi dengan arahan preprosesor, gaya C
jwrush

1
Er. Saya bodoh. Anda bermaksud kelas statis untuk metode ekstensi HOLDING, yang, tentu saja, adalah bagaimana Anda harus melakukannya. Ya, tentu saja, Anda menginginkan kelas statis untuk tujuan itu. Itu menyelinap di pikiranku: dan ini menunjukkan bahwa C # tidak ditujukan untuk IoC. :)
jwrush

Ya, Anda benar, jika ada budaya dalam proyek yang ada itu akan lebih merusak daripada membantu mengubah cara melakukan sesuatu.
Tidak

5

Kelas statis terkadang disalahgunakan dan harus:

  • singleton (di mana kelas non-statis memiliki anggota statis dan variabel Instance statis publik untuk mengambil / membuat hanya satu kali.
  • metode di kelas lain (di mana negara penting). Jika Anda memiliki anggota yang tidak menggunakan data dari kelas itu, mungkin itu tidak boleh menjadi bagian dari kelas itu.

Ini juga bisa disebut fungsi 'utilitas', dan bagian dari kelas utilitas. Kelas utilitas adalah kelas yang hanya berisi metode statis dan berfungsi sebagai fungsi pembantu tanpa konteks apa pun.


@topomorto Karena kelas tidak boleh di-instantiated oleh konstruktornya yang menghasilkan banyak objek / instance, tetapi dengan metode khusus (biasanya instance ()) <yang mengembalikan selalu instance yang sama, dipakai setelah panggilan pertama ke instance ().
Michel Keijzers

@topomorto Saya baru saja memeriksa dan Anda benar, hanya beberapa anggota yang statis (variabel instan dan fungsi instance). Saya akan mengubah jawaban saya sesuai; terima kasih telah menyebutkan.
Michel Keijzers

4

Metode statis baik untuk digunakan dan memiliki tempat yang tepat dalam pemrograman. Sepertinya arsitek Anda memiliki kerangka pengujian yang tidak sepenuhnya mendukung metode statis. Jika kode Anda adalah bagian dari proyek yang lebih besar, maka penting untuk memenuhi pedoman arsitek. Namun, jangan biarkan proyek ini menghalangi Anda dari menggunakan metode statis ketika tepat untuk melakukannya.


1

Saya telah menggunakan properti statis untuk hal-hal yang umum untuk semua instance kelas. Dan saya telah menggunakan metode statis untuk mendapatkan kelompok objek kelas. Saya sama sekali tidak ahli tetapi ini telah bekerja untuk saya sejauh ini.

Contoh PHP:

class vendorData {
  private static $data_table = 'vendor_data'; // static property
  private $id; // instance property
  private $name; // instance property

  public function __construct($vendor_id) {
    if(!self::validId($vendor_id) ) { // static method
      return false; // id doesn't exist
    }
    $this->id = $vendor_id; // id has been validated
    $this->getProperties(); // object method
  }

  private static function validId($vendor_id) {
    // send db query to find if the id exists
    // return true/false;
  }

  private function getProperties() { // object method
    $sql = "SELECT * FROM `{self::$data_table}` // using static property
        WHERE `id` = {$this->id}"; // using object instance property
    // get resultset
    foreach($result as $property => $value) {
      $this->$property = $value; // object instance properties all set
    }
  }

  // and here
  public static function getBy($property,$value) { // static method to return object array
    $sql = "SELECT `id` FROM `{self::$data_table}` // using static property
      WHERE `$property` = '$value'";
    // send query, get $ids array
    $obj_array = array();
    foreach($ids as $id) {
      // create array of current class objects using special static keyword
      // meaning of static here is different than in property/method declarations
      $obj_array[$id] = new static($id);
    }
    return $obj_array;
  }
}

1

Saya akan mengatakan prinsip-prinsip yang mereka miliki baik-baik saja tetapi pernyataan (jangan gunakan statika) mungkin salah. Berapa cakupan kode Anda? jika angkanya tinggi dan Anda merasa nyaman dengan unit testing aplikasi Anda, maka Anda baik-baik saja. Jika tidak, maka saya sarankan meninjau kode. Anda mungkin menemukan kelas statis adalah alasannya atau tidak, itu akan tergantung pada banyak hal.


-3

Kelas dengan metode statis menyalahgunakan prinsip-prinsip OOP. Ini bukan OOP, ini COP - pemrograman berorientasi kelas.

Mereka jarang memiliki "kepribadian" yang jelas (saya menggunakan metafora manusia favorit saya di sini), atau identitas. Jadi mereka tidak tahu siapa mereka. Poin ini saja sudah cukup untuk menyingkirkan konsep ini dalam OOP, tetapi ada lebih banyak dari mereka.

Yang berikutnya adalah konsekuensi dari poin pertama. Karena kelas seperti itu tidak tahu siapa mereka, mereka cenderung dari besar ke besar.

Yang ketiga membuat kode Anda benar-benar tidak dapat dipelihara. Penggunaan metode statis memperkenalkan dependensi tersembunyi . Mereka muncul di semua tempat, dan Anda tidak pernah tahu apa yang terjadi di kelas Anda. Anda tidak bisa memastikan hanya dengan melihat tanda tangan konstruktor.

Perlahan, tetapi tak terhindarkan, kode Anda semakin tidak kohesif, karena dependensi tersembunyi tidak terkontrol dengan baik. Mereka tampak tidak terlihat. Dan sangat mudah untuk menambahkan yang lain! Anda tidak perlu mengubah tanda tangan metode apa pun. Yang harus Anda lakukan adalah memanggil metode statis. Dan apa yang diikuti oleh kode jelek ...

Ok, Anda mungkin sudah menebak. Kopling ketat adalah petugas yang sering kohesi rendah. Jika ada banyak klien menggunakan beberapa kelas, maka kopling semakin ketat. Dan ada godaan besar dalam menggunakan kelas atau metode yang sudah ditulis yang hanya membutuhkan perbaikan kecil. Hanya satu metode flag-parameter.

Apa yang harus digunakan daripada metode statis? Nah, saran saya adalah OOP. Mengapa tidak mencobanya?

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.