Pertanyaan ini subyektif tapi saya hanya ingin tahu bagaimana kebanyakan programmer mendekati ini. Sampel di bawah ini dalam pseudo-C # tetapi ini harus berlaku untuk Java, C ++, dan bahasa OOP lainnya juga.
Lagi pula, ketika menulis metode helper di kelas saya, saya cenderung menyatakannya sebagai statis dan hanya meneruskan kolom jika metode helper membutuhkannya. Misalnya, mengingat kode di bawah ini, saya lebih suka menggunakan Metode Panggilan # 2 .
class Foo
{
Bar _bar;
public void DoSomethingWithBar()
{
// Method Call #1.
DoSomethingWithBarImpl();
// Method Call #2.
DoSomethingWithBarImpl(_bar);
}
private void DoSomethingWithBarImpl()
{
_bar.DoSomething();
}
private static void DoSomethingWithBarImpl(Bar bar)
{
bar.DoSomething();
}
}
Alasan saya melakukan ini adalah karena hal itu menjelaskan (paling tidak di mata saya) bahwa metode helper memiliki efek samping yang mungkin terjadi pada objek lain - bahkan tanpa membaca implementasinya. Saya menemukan bahwa saya dapat dengan cepat grok metode yang menggunakan praktik ini dan dengan demikian membantu saya dalam debugging hal-hal.
Yang mana yang Anda sukai untuk dilakukan dalam kode Anda sendiri dan apa alasan Anda melakukannya?
Jawaban:
Ini sangat tergantung. Jika nilai yang digunakan oleh pembantu Anda adalah primitif, maka metode statis adalah pilihan yang baik, seperti yang ditunjukkan Péter.
Jika mereka kompleks, maka SOLID berlaku, lebih khusus S , yang saya dan D .
Contoh:
Ini tentang masalah Anda. Anda dapat membuat
makeEveryBodyAsHappyAsPossible
metode statis, yang akan mengambil parameter yang diperlukan. Pilihan lain adalah:Sekarang
OurHouse
tidak perlu tahu tentang seluk-beluk aturan distribusi cookie. Itu harus sekarang hanya objek, yang mengimplementasikan aturan. Implementasinya diabstraksi menjadi sebuah objek, siapa yang bertanggung jawab untuk menerapkan aturan tersebut. Objek ini dapat diuji secara terpisah.OurHouse
dapat diuji dengan menggunakan tiruan belakaCookieDistributor
. Dan Anda dapat dengan mudah memutuskan untuk mengubah aturan distribusi cookie.Namun, berhati-hatilah agar Anda tidak berlebihan. Sebagai contoh, memiliki sistem 30 kelas yang kompleks bertindak sebagai implementasi dari
CookieDistributor
, di mana setiap kelas hanya memenuhi tugas kecil, tidak terlalu masuk akal. Interpretasi saya terhadap SRP adalah bahwa hal itu tidak hanya menentukan bahwa setiap kelas mungkin hanya memiliki satu tanggung jawab, tetapi juga bahwa satu tanggung jawab tunggal harus dijalankan oleh satu kelas tunggal.Dalam kasus primitif atau objek yang Anda gunakan seperti primitif (misalnya objek yang mewakili titik dalam ruang, matriks atau sesuatu), kelas helper statis sangat masuk akal. Jika Anda memiliki pilihan, dan itu benar-benar masuk akal, maka Anda mungkin benar-benar mempertimbangkan untuk menambahkan metode ke kelas yang mewakili data, misalnya masuk akal jika
Point
memilikiadd
metode. Sekali lagi, jangan berlebihan.Jadi tergantung pada masalah Anda, ada berbagai cara untuk menyelesaikannya.
sumber
Merupakan idiom yang terkenal untuk mendeklarasikan metode kelas utilitas
static
, sehingga kelas seperti itu tidak perlu dipakai. Mengikuti idiom ini membuat kode Anda lebih mudah dipahami, yang merupakan hal yang baik.Ada batasan serius untuk pendekatan ini: metode / kelas seperti itu tidak dapat dengan mudah diejek (meskipun AFAIK setidaknya untuk C # ada kerangka kerja mengejek yang dapat mencapai hal ini, tetapi mereka tidak biasa dan setidaknya beberapa dari mereka adalah komersial). Jadi, jika metode helper memiliki ketergantungan eksternal (misalnya DB) yang membuatnya - sehingga peneleponnya - sulit untuk diuji unit, lebih baik untuk menyatakannya non-statis . Ini memungkinkan injeksi ketergantungan, sehingga membuat penelepon metode lebih mudah untuk unit test.
Memperbarui
Klarifikasi: pembicaraan di atas tentang kelas utilitas, yang hanya berisi metode pembantu tingkat rendah dan (biasanya) tidak ada status. Metode pembantu di dalam kelas non-utilitas stateful adalah masalah yang berbeda; permintaan maaf karena salah mengartikan OP.
Dalam hal ini, saya merasakan bau kode: metode kelas A yang beroperasi terutama pada instance dari kelas B mungkin sebenarnya memiliki tempat yang lebih baik di kelas B. Tetapi jika saya memutuskan untuk menyimpannya di tempat itu, saya lebih suka opsi 1, karena lebih sederhana dan lebih mudah dibaca.
sumber
Saya lebih suka # 1 (
this->DoSomethingWithBarImpl();
), kecuali tentu saja metode helper tidak perlu akses ke data / implementasi instancestatic t_image OpenDefaultImage()
.antarmuka publik dan implementasi pribadi dan anggota terpisah. program akan jauh lebih sulit dibaca jika saya memilih # 2. dengan # 1, saya selalu memiliki anggota dan contoh tersedia. dibandingkan dengan banyak implementasi berbasis OO, saya cenderung menggunakan banyak encapsualtion, dan sangat sedikit anggota per kelas. sejauh efek samping - saya setuju dengan itu, sering ada validasi negara yang memperluas dependensi (misalnya argumen yang harus dilewati).
# 1 jauh lebih mudah untuk dibaca, dipelihara, dan memiliki sifat kinerja yang baik. tentu saja, akan ada kasus di mana Anda dapat membagikan implementasi:
Jika # 2 adalah solusi umum yang baik (misalnya default) dalam basis kode, saya akan khawatir tentang struktur desain: apakah kelas melakukan terlalu banyak? apakah tidak ada enkapsulasi yang cukup atau tidak cukup digunakan kembali? Apakah level abstraksinya cukup tinggi?
terakhir, # 2 tampaknya berlebihan jika Anda menggunakan bahasa OO di mana mutasi didukung (misalnya
const
metode).sumber