Tidak bisakah saya menggunakan semua metode statis?

64

Apa perbedaan antara kedua metode UpdateSubject di bawah ini? Saya merasa menggunakan metode statis lebih baik jika Anda hanya ingin beroperasi pada entitas. Dalam situasi apa saya harus menggunakan metode non-statis?

public class Subject
{
    public int Id {get; set;}
    public string Name { get; set; }

    public static bool UpdateSubject(Subject subject)
    {
        //Do something and return result
        return true;
    }
    public bool UpdateSubject()
    {
        //Do something on 'this' and return result
        return true;
    }
}

Saya tahu saya akan mendapatkan banyak tendangan dari komunitas untuk pertanyaan yang sangat menjengkelkan ini, tetapi saya tidak bisa berhenti bertanya.

Apakah ini menjadi tidak praktis ketika berhadapan dengan warisan?

Pembaruan:
Ini terjadi di tempat kerja kami sekarang. Kami sedang mengerjakan aplikasi web asp.net 6 bulan dengan 5 pengembang. Arsitek kami memutuskan untuk menggunakan semua metode statis untuk semua API. Alasannya menjadi metode statis adalah ringan dan menguntungkan aplikasi web dengan menjaga server turun.

Alexander
sumber
9
Rich Hickey akan mendorong sesuatu yang non-idiomatis seperti itu (semua metode statis). Jika Anda menyukai gaya fungsional, Anda mungkin juga menggunakan bahasa fungsional;) ​​Tidak semua perangkat lunak dimodelkan sebagai objek.
Pekerjaan
13
@ Pekerjaan: Saya tidak benar-benar melihat bagaimana ini berfungsi - ini prosedural.
Aaronaught
2
@ Pekerjaan: Kelas ini tidak bisa diubah.
Aaronaught
3
@ DonalFellows: Tentu saja Anda bisa, C # dan F # keduanya adalah paradigma campuran. Tetapi faktanya tetap, metode statis! = Pemrograman fungsional. FP berarti fungsi passing / rantai, tipe data yang tidak dapat diubah, penghindaran efek samping, dll. Itu benar-benar berlawanan dengan apa yang dilakukan oleh cuplikan kode dalam OP.
Aaronaught
4
"Alasannya menjadi metode statis adalah ringan dan menguntungkan aplikasi web dengan menjaga server turun". Itu salah. Menjaga server memuat?
mamcx

Jawaban:

87

Saya akan membahas masalah metode statis yang paling nyata dengan parameter "ini" eksplisit:

  1. Anda kehilangan pengiriman virtual dan kemudian polimorfisme. Anda tidak pernah bisa menimpa metode itu di kelas turunan. Tentu saja Anda dapat mendeklarasikan metode new( static) di kelas turunan, tetapi kode apa pun yang mengaksesnya harus mengetahui seluruh hierarki kelas dan melakukan pengecekan dan pengecoran secara eksplisit, yang persisnya harus dihindari oleh OO .

  2. Semacam ekstensi # 1, Anda tidak dapat mengganti instance kelas dengan antarmuka , karena antarmuka (dalam kebanyakan bahasa) tidak dapat mendeklarasikan staticmetode.

  3. Verbositas yang tidak perlu. Mana yang lebih mudah dibaca: Subject.Update(subject)atau adil subject.Update()?

  4. Pemeriksaan argumen. Sekali lagi tergantung pada bahasa, tetapi banyak yang akan mengkompilasi pemeriksaan implisit untuk memastikan bahwa thisargumen tidak nulluntuk mencegah bug referensi nol dari menciptakan kondisi runtime yang tidak aman (semacam buffer overrun). Tidak menggunakan metode instan, Anda harus menambahkan centang ini secara eksplisit di awal setiap metode.

  5. Ini membingungkan. Ketika seorang programmer yang normal dan masuk akal melihat suatu staticmetode, ia secara alami akan berasumsi bahwa itu tidak memerlukan contoh yang valid (kecuali dibutuhkan beberapa contoh, seperti metode perbandingan atau kesetaraan, atau diharapkan dapat beroperasi pada nullreferensi) . Melihat metode statis yang digunakan dengan cara ini akan membuat kita melakukan pengambilan ganda atau mungkin tiga kali lipat, dan setelah ke-4 atau ke-5 kita akan merasa stres dan marah dan tuhan membantu Anda jika kami tahu alamat rumah Anda.

  6. Ini bentuk duplikasi. Apa yang sebenarnya terjadi ketika Anda memanggil metode instance adalah bahwa kompiler atau runtime mencari metode dalam tabel metode tipe dan memanggilnya menggunakan thissebagai argumen. Anda pada dasarnya menerapkan kembali apa yang sudah dilakukan oleh kompiler. Anda melanggar KERING , mengulangi parameter yang sama berulang-ulang dalam metode yang berbeda saat itu tidak diperlukan.

Sulit untuk memahami alasan bagus untuk mengganti metode instan dengan metode statis. Tolong jangan.

Aaronaught
sumber
5
+1 untuk baris terakhir Anda sendiri. Saya berharap lebih banyak orang akan berpikir "metode contoh" sebelum mereka berpikir "metode statis".
Stuart Leyland-Cole
4
+1. Saya akan menambahkan bahwa metode statis membuatnya sulit untuk tidak mungkin menulis tes, seperti dalam kebanyakan kasus Anda tidak dapat mengejek mereka: sekali setiap bagian dari kode Anda tergantung pada metode statis, Anda tidak dapat menggantikannya dengan no- op dalam tes Anda. Contoh utama dalam dunia .NET akan seperti kelas File, FileInfodan DirectoryInfo(dan pada kenyataannya, ada perpustakaan yang menyembunyikan mereka di belakang antarmuka yang kemudian dapat disuntikkan sesuai kebutuhan dan dihina dalam tes).
sm
Saya pikir poin Anda tentang polimorfisme / warisan diperdebatkan. seseorang tidak boleh menggunakan warisan untuk penggunaan kembali kode, jadi itu tidak relevan. bagian warisan juga meragukan. dalam kebanyakan bahasa modern, tanda tangan metode bersifat polimorfik. jika Anda mengambil pendekatan fungsional Anda mulai membagikan metode dan Anda menyusun metode kompleks dari yang sederhana yang dapat dipertukarkan berdasarkan antarmuka mereka. ada basiaclly tidak ada kelemahan untuk metode statis yang tidak diimbangi dengan hanya merancang dengan mereka dalam pikiran, sama seperti dengan OOP.
sara
@sm itu tidak benar. jika Anda memiliki ketergantungan yang keras pada APA SAJA, statis atau tidak, itu tidak bisa dalam unit test, maka itu tidak dapat diuji, titik. statis tidak menyebabkan ini. metode statis dapat disuntikkan dengan cara yang sama seperti kelas yang mewakili koneksi db. Anda mengasumsikan bahwa "statis" berarti "ketergantungan statis ditambah hard tersembunyi menyentuh negara global dan sumber daya eksternal". itu tidak adil.
sara
@ Kai mencoba menyuntikkan metode statis yang melakukan Y bukan X, apa pun X dan Y. Anda tidak perlu mengambil ketergantungan pada apa pun yang eksternal untuk dikacaukan. Mungkin Anda hanya tertarik menguji beberapa aspek yang tidak memerlukan perhitungan X yang panjang untuk dilakukan. Bagaimana cara menyuntikkan metode statis mewah Anda tanpa membuat pembungkus? Melewati fungsi sekitar tidak didukung oleh setiap bahasa. Metode statis memiliki kasus penggunaannya dan saya menggunakannya ketika masuk akal untuk melakukannya . Ini, seperti yang selalu terjadi, kasus "hanya karena Anda tidak dapat selalu berarti Anda harus".
sm
13

Anda sudah cukup banyak menggambarkan dengan tepat bagaimana Anda melakukan OOP di C, di mana hanya metode statis yang tersedia, dan "ini" adalah penunjuk struct. Dan ya, Anda dapat melakukan run time polymorphism di C dengan menentukan pointer fungsi selama konstruksi untuk disimpan sebagai salah satu elemen dari struct. Metode instan yang tersedia dalam bahasa lain hanyalah gula sintaksis yang pada dasarnya melakukan hal yang persis sama di bawah tenda. Beberapa bahasa, seperti python, berada di tengah-tengah, di mana parameter "diri" terdaftar secara eksplisit, tetapi sintaks khusus untuk memanggilnya menangani warisan dan polimorfisme untuk Anda.

Karl Bielefeldt
sumber
FWIW, dengan C Anda dapat melakukan pengiriman virtual seperti ini: obj->type->mthd(obj, ...);dan itu hampir sama dengan apa yang terjadi dengan pengiriman virtual dalam bahasa lain (tetapi di belakang layar).
Donal Fellows
@ Karl Bisakah Anda memberikan semacam referensi tertulis untuk mulai menggali lebih dalam?
Jorge Lavín
Anda mungkin ingin melihat GObject sebagai implementasi referensi yang baik.
Karl Bielefeldt
10

Masalah dengan metode statis muncul saat Anda membutuhkan sub-kelas.

Metode statis tidak dapat ditimpa dalam sub-kelas, maka kelas baru Anda tidak dapat memberikan implementasi baru dari metode tersebut, membuatnya kurang berguna.


sumber
2
Ini bukan selalu masalah. Beberapa bahasa menyediakan mekanisme lain (metode non-virtual dalam C ++ dan C #) untuk mencapai hal yang sama secara sengaja - C # bahkan menyediakan metode "disegel" untuk memperluas ide ini! Jelas, Anda tidak akan melakukan ini hanya untuk itu, tapi ini teknik yang baik untuk diperhatikan ...
Shog9
@Steve, itu tidak menggantikan, karena Anda masih dapat memanggil kedua metode secara langsung.
@Steve, di Java, metode statis tidak bisa diganti.
@ Thorbjørn - pertama, pertanyaannya tidak ditandai dengan Java, atau bahasa OOP spesifik lainnya. Lebih penting lagi, saya tidak mengatakan Anda bisa mengganti fungsi anggota statis. Saya mencoba menggunakan analogi untuk menyampaikan maksud. Karena saya jelas gagal, komentar dihapus.
Steve314
2
Dalam arti tertentu, ini masih "implementasi metode baru". Hanya saja tidak dalam arti OOP standar. Ini terasa seperti saya katakan "kata-kata Anda tidak sempurna juga, nur-nur-na-nur-nur" ;-)
Steve314
7

Jika Anda mendeklarasikan suatu metode static, Anda tidak harus membuat instance objek dari kelas (menggunakan newkata kunci) untuk menjalankan metode tersebut. Namun, Anda tidak dapat merujuk ke variabel anggota apa pun kecuali mereka juga statis, dalam hal ini variabel anggota tersebut milik kelas, bukan objek instantiated khusus dari kelas.

Dengan kata lain, statickata kunci menyebabkan deklarasi menjadi bagian dari definisi kelas, sehingga menjadi titik referensi tunggal di semua instance kelas (objek yang dipakai dari kelas).

Ini mengikuti, kemudian, bahwa jika Anda ingin beberapa salinan berjalan dari kelas Anda, dan Anda tidak ingin negara (variabel anggota) untuk dibagikan di antara semua salinan berjalan Anda (yaitu setiap objek memegang keadaan uniknya sendiri), maka Anda tidak dapat mendeklarasikan variabel anggota itu statis.

Secara umum, Anda harus menggunakan statickelas dan metode hanya ketika Anda membuat metode utilitas yang menerima satu atau lebih parameter, dan mengembalikan objek semacam itu, tanpa efek samping (mis. Perubahan ke variabel keadaan di kelas)

Robert Harvey
sumber
1
Saya pikir OP mengerti apa staticartinya, dia bertanya mengapa tidak hanya menyatakan semuanya statis.
Ed S.
1
Dia adalah lewat di sebuah instance dari Subject- tetapi sebagai parameter eksplisit, bukan implisit thisparameter.
Steve314
Ya, ya ... tapi saya rasa saya tidak mengerti maksud Anda.
Ed S.
@ Ed - hanya itu yang bisa Anda lakukan cukup banyak melalui parameter eksplisit yang Anda bisa melalui thisparameter implisit . Ada perbedaan dalam harapan, tetapi di luar warisan, tidak ada perbedaan nyata dalam apa yang dapat Anda lakukan. Sebagai contoh, anggota non-statis dapat diakses - melalui parameter eksplisit.
Steve314
Saya beroperasi dengan asumsi bahwa Anda tidak bisa mendapatkan anggota pribadi dari argumen dalam C # bahkan melalui metode statis yang dideklarasikan di kelas yang sama (seperti yang Anda dapat dalam C ++). Tidak yakin mengapa saya berpikir begitu, tetapi saya salah.
Ed S.
3

Alasan orang berpendapat bahwa 'metode statis menunjukkan desain buruk' belum tentu karena metode, itu sebenarnya data statis, implisit atau eksplisit. Secara implisit maksud saya SETIAP keadaan dalam program yang tidak terkandung dalam nilai atau parameter pengembalian. Mengubah keadaan dalam fungsi statis adalah kemunduran untuk pemrograman prosedural. Namun jika fungsi tidak mengubah keadaan, atau mendelegasikan modifikasi negara ke fungsi objek komponen, itu sebenarnya lebih merupakan paradigma fungsional daripada prosedural.

Jika Anda tidak mengubah status, metode dan kelas statis dapat memiliki banyak manfaat. Itu membuatnya jauh lebih mudah untuk memastikan metode murni, dan dengan demikian bebas dari efek samping dan kesalahan yang sepenuhnya dapat direproduksi. Ini juga memastikan bahwa berbagai metode dalam beberapa aplikasi menggunakan perpustakaan bersama dapat dipastikan mereka akan mendapatkan hasil yang sama dengan input yang sama, membuat pelacakan kesalahan dan pengujian unit menjadi lebih mudah.

Pada akhirnya tidak ada perbedaan dalam praktik antara objek berukuran besar yang biasa terlihat seperti 'StateManager' dan data statis atau global. Manfaat dari metode statis yang digunakan dengan benar adalah mereka dapat menunjukkan maksud penulis untuk tidak mengubah keadaan ke revisi nanti.

Mathieson
sumber
1
Pernyataan Anda "... adalah kemunduran untuk pemrograman prosedural ..." membuat saya berpikir bahwa Anda menganggapnya sangat buruk, saya kira itu adalah bagian dari OO dalam arti tertentu.
NoChance
making ... unit testing much easier.Tidak, tidak akan. Itu membuatnya membuat kode apa pun yang memanggil metode statis tidak mungkin untuk unit test, karena Anda tidak dapat mengisolasinya dari metode statis. Panggilan ke metode statis menjadi ketergantungan hardcoded ke kelas itu.
StuperUser
2

Tergantung pada bahasa dan apa yang Anda coba lakukan, jawabannya mungkin tidak ada banyak perbedaan, tetapi staticversi ini memiliki sedikit lebih banyak kekacauan.

Seperti sintaksis contoh Anda menyarankan Java atau C #, saya pikir Thorbjørn Ravn Andersen benar untuk menunjukkan masalah utama (dengan keterlambatan mengikat). Dengan metode statis, tidak ada parameter "khusus" untuk pengikatan yang terlambat, jadi Anda tidak dapat memiliki pengikatan yang terlambat.

Akibatnya, metode statis hanyalah fungsi dalam modul, modul itu memiliki nama yang sama dengan kelas - itu sebenarnya bukan metode OOP sama sekali.

Steve314
sumber
2

Anda pada dasarnya mengalahkan seluruh titik objek ketika Anda melakukan ini. Ada alasan bagus mengapa kita telah banyak bergeser dari kode prosedural ke kode berorientasi objek.

Saya tidak akan pernah mendeklarasikan metode statis yang menggunakan tipe kelas sebagai parameter. Itu hanya membuat kode lebih kompleks tanpa keuntungan.

Loren Pechtel
sumber
3
Anda mungkin melakukannya jika Anda melewati sebuah objectke staticmetode, dan kembali baru object. Pemrogram fungsional melakukan ini sepanjang waktu.
Robert Harvey
pertanyaan: apakah Anda menganggap Mathkelas statis "kompleks tanpa perolehan", atau apakah Anda lebih suka jika semua tipe angka memiliki metode virtual yang mendefinisikan nilai absolut, negasi, penambahan, kuadrat, akar sembarang, dan seterusnya? Saya kira tidak. objek rapi ketika Anda perlu menyimpan keadaan bisa berubah yang tersembunyi di mana Anda perlu menegakkan beberapa invarian. menumbuk bersama setiap metode yang dapat dipercaya yang beroperasi pada suatu tipe ke dalam tipe itu sendiri, ITULAH sesuatu yang mengarah pada kode yang kompleks dan tidak dapat dipertahankan. Saya setuju dengan Robert, Anda mungkin ingin melihat bagaimana programmer fungsional bekerja, itu bisa menjadi pembuka mata nyata!
sara
@ai Seperti yang saya katakan, cukup banyak. Kelas Matematika adalah pengecualian yang masuk akal, meskipun melampirkannya ke tipe numerik tidak akan menjadi ide yang buruk.
Loren Pechtel
2

Ada banyak jawaban bagus di sini, dan mereka jauh lebih banyak wawasan dan pengetahuan daripada apa pun yang bisa saya berikan sebagai jawaban, tapi saya merasa ada sedikit sesuatu yang tidak ditekankan:

"Arsitek kami memutuskan untuk menggunakan semua metode statis untuk semua API. Alasannya karena metode statis itu ringan dan menguntungkan aplikasi web dengan menjaga server memuat ."

(Penekanan berani adalah milikku)

2c saya pada bagian pertanyaan ini adalah ini:

Secara teoritis, apa yang dikatakan benar ada: memanggil metode statis hanya memiliki overhead sebenarnya memanggil metode itu. Memanggil metode non-statis (instance) memiliki overhead tambahan pertama instantiating objek, dan pada beberapa titik, menghancurkan instance (baik secara manual atau melalui beberapa bentuk pengumpulan sampah otomatis, tergantung pada platform yang digunakan).

Drama ini sedikit menganjurkan setan: kita bisa melangkah lebih jauh dan mengatakan hal-hal seperti:

  • ini bisa menjadi sangat buruk jika sebuah instance dibuat untuk setiap pemanggilan metode (instance) (bukan hanya membiarkannya statis dan memanggilnya seperti itu)

  • tergantung dari kerumitan konstruktor, tipe hirarki, anggota contoh lain dan faktor tidak dikenal lainnya, overhead tambahan dari pemanggilan metode non-statis dapat bervariasi dan menjadi sangat besar

Sebenarnya, IMHO, poin-poin di atas (dan pendekatan umum "mari kita gunakan statika karena mereka lebih cepat") adalah argumen manusia jerami / penilaian:

  • jika kodenya bagus, dan, lebih spesifik pada argumen ini, jika instans dibuat hanya jika perlu (dan dihancurkan dengan cara yang optimal), maka Anda tidak mendapatkan overhead tambahan dari menggunakan metode insance jika diperlukan (karena jika Anda hanya membuat objek yang diperlukan, itu akan dibuat bahkan jika metode itu dinyatakan statis di mana lagi = overhead instanciation yang sama)

  • dengan menyalahgunakan deklarasi metode statis dengan cara ini, dimungkinkan untuk menyembunyikan beberapa masalah dengan kode Anda sehubungan dengan bagaimana instance dibuat (karena metode ini statis, kode instanciation yang salah dapat dilewatkan tanpa diketahui sampai nanti, dan itu tidak pernah baik).

Shivan Dragon
sumber
2

Ini adalah pertanyaan yang sangat menarik yang cenderung memiliki jawaban yang sangat berbeda tergantung pada komunitas yang Anda tanyakan. Jawaban lain tampaknya bias C # atau java: bahasa pemrograman yang (sebagian besar) berorientasi objek murni dan memiliki semacam pandangan idiomatis tentang apa orientasi objek.

Di komunitas lain, seperti C ++, orientasi objek ditafsirkan dengan lebih bebas. Beberapa ahli yang sudah mengetahui telah mempelajari subjek dan, sebenarnya, menyimpulkan bahwa fungsi bebas meningkatkan enkapsulasi (penekanan adalah milikku):

Kita sekarang telah melihat bahwa cara yang masuk akal untuk mengukur jumlah enkapsulasi dalam kelas adalah dengan menghitung jumlah fungsi yang mungkin rusak jika implementasi kelas berubah. Karena itu, menjadi jelas bahwa kelas dengan fungsi n anggota lebih dienkapsulasi daripada kelas dengan fungsi anggota n +1. Dan pengamatan itulah yang membenarkan argumen saya untuk lebih memilih fungsi non-anggota non-teman daripada fungsi anggota

Scott Meyers

Bagi mereka yang tidak terbiasa dengan terminologi C ++:

  • fungsi anggota = metode
  • fungsi non-anggota = metode statis
  • non-teman = hanya menggunakan API publik
  • non-member non-friend function = metode statis yang hanya menggunakan API publik

Sekarang, untuk menjawab pertanyaan Anda:

Tidak bisakah saya menggunakan semua metode statis?

Tidak, Anda tidak harus selalu menggunakan metode statis.

Tapi, Anda harus menggunakannya kapan pun Anda hanya perlu menggunakan API publik dari suatu kelas.

authchir
sumber
-3

di Jawa ...

Metode statis tidak ditimpa tetapi disembunyikan sebagai gantinya dan itu akan menjadi perbedaan besar (masalah?) Dalam kasus memperluas kelas.

Di sisi lain saya perhatikan bahwa programmer Java memiliki kecenderungan untuk berpikir bahwa semua HARUS menjadi objek, tanpa benar-benar mengerti mengapa, dan saya tidak setuju.

Statis harus digunakan untuk kode khusus untuk kelas. Statis tidak bekerja dengan baik dengan warisan.

beberapa contoh penggunaan metode statis yang baik adalah fungsi independen tanpa efek samping.

juga melihat kata kunci disinkronkan ...

Nicolas
sumber
2
Bagaimana metode statis ini bersembunyi dan di mana perbedaan dan masalah ini muncul ketika memperluas kelas? Bagaimana cara sinkronisasi disinkronkan dengan ini? Di mana masalah statis dan warisan dihadapi? Bisakah Anda memberikan beberapa metode statis yang baik dan buruk di perpustakaan inti Java dan menjelaskan mengapa masing-masing kasus?