Penebang adalah apa yang kita sebut "keprihatinan lintas sektoral." Mereka menghasilkan teknik seperti Pemrograman Berorientasi Aspek; jika Anda memiliki cara untuk menghias kelas Anda dengan atribut atau melakukan beberapa kode tenun, maka itu adalah cara yang baik untuk mendapatkan kemampuan logging sambil menjaga objek dan daftar parameter Anda "murni."
Satu-satunya alasan Anda mungkin ingin memasukkan logger adalah jika Anda ingin menentukan implementasi logging yang berbeda, tetapi sebagian besar kerangka kerja logging memiliki fleksibilitas untuk memungkinkan Anda mengonfigurasinya, katakanlah, untuk target logging yang berbeda. (file log, Windows Event Manager, dll.)
Karena alasan ini, saya lebih suka menjadikan logging sebagai bagian alami dari sistem, daripada menyerahkan logger ke setiap kelas untuk tujuan logging. Jadi yang biasanya saya lakukan adalah mereferensikan namespace logging yang sesuai, dan cukup gunakan logger di kelas saya.
Jika Anda masih ingin meneruskan logger, preferensi saya adalah Anda menjadikannya parameter terakhir dalam daftar parameter (menjadikannya parameter opsional, jika mungkin). Setelah itu menjadi parameter pertama tidak masuk akal; parameter pertama harus yang paling penting, yang paling relevan dengan operasi kelas.
Dalam bahasa dengan fungsi yang berlebihan, saya berpendapat bahwa semakin besar kemungkinan argumen menjadi opsional, semakin jauh seharusnya. Ini menciptakan konsistensi ketika Anda membuat kelebihan di mana mereka hilang:
Dalam bahasa fungsional, kebalikannya lebih berguna - semakin besar kemungkinan Anda untuk memilih beberapa default, semakin jauh seharusnya. Ini membuatnya lebih mudah untuk mengkhususkan fungsi dengan hanya menerapkan argumen padanya:
Namun seperti yang disebutkan dalam jawaban lain, Anda mungkin tidak ingin secara eksplisit melewati logger dalam daftar argumen setiap kelas dalam sistem.
sumber
Anda pasti bisa menghabiskan banyak waktu untuk merekayasa masalah ini.
Untuk bahasa dengan implementasi logging kanonik, cukup instantiate kanger logger langsung di setiap kelas.
Untuk bahasa tanpa implementasi kanonik, cobalah untuk menemukan kerangka fasad logging dan patuhi itu. slf4j adalah pilihan yang baik di Jawa.
Secara pribadi saya lebih suka tetap berpegang pada implementasi logging beton tunggal dan mengirim semuanya ke syslog. Semua alat analisis log yang baik mampu menggabungkan log sysout dari beberapa server aplikasi ke dalam laporan yang komprehensif.
Ketika tanda tangan fungsi menyertakan satu atau dua layanan dependensi serta beberapa argumen "nyata", saya menempatkan dependensi terakhir:
int calculateFooBarSum(int foo, int bar, IntegerSummationService svc)
Karena sistem saya cenderung hanya memiliki lima atau lebih sedikit layanan seperti itu, saya selalu memastikan layanan dimasukkan dalam urutan yang sama di semua tanda tangan fungsi. Urutan alfabet sama baiknya dengan yang lainnya. (Selain itu: mempertahankan pendekatan metodologis ini untuk penanganan mutex juga akan mengurangi peluang Anda mengembangkan kebuntuan.)
Jika Anda mendapati diri Anda menyuntikkan lebih dari selusin ketergantungan di seluruh aplikasi Anda, maka sistem mungkin perlu dipecah menjadi beberapa subsistem yang terpisah (berani saya katakan layanan mikro?).
sumber
Penebang agak merupakan kasus khusus karena mereka harus tersedia secara harfiah di mana-mana.
Jika Anda telah memutuskan bahwa Anda ingin meneruskan logger ke konstruktor setiap kelas, maka Anda harus menetapkan konvensi yang konsisten untuk bagaimana Anda melakukan itu (misalnya, selalu parameter pertama, selalu lulus dengan referensi, daftar inisialisasi konstruktor selalu dimulai dengan m_logger (theLogger), dll). Apa pun yang akan digunakan di seluruh basis kode Anda akan mendapat manfaat dari konsistensi suatu hari nanti.
Atau, Anda bisa membuat setiap kelas instantiate objek logger mereka sendiri, tanpa perlu apa-apa untuk dilewatkan. Logger mungkin perlu mengetahui beberapa hal "dengan sihir" agar bisa berfungsi, tetapi meng-hardcoding sebuah filepath dalam definisi kelas berpotensi menjadi jauh lebih mudah dirawat dan tidak terlalu membosankan daripada meneruskannya dengan benar ke ratusan kelas yang berbeda, dan bisa dibilang jauh lebih sedikit jahat daripada menggunakan variabel global untuk memotong kata kebosanan. (Harus diakui, para penebang adalah satu dari sedikit kasus penggunaan yang sah untuk variabel global)
sumber
Saya setuju dengan mereka yang menyarankan bahwa logger harus diakses secara statis daripada diteruskan ke kelas. Namun jika ada alasan kuat Anda ingin lulus dalam (kasus mungkin berbeda ingin log ke lokasi yang berbeda atau sesuatu) maka saya akan menyarankan Anda tidak lulus itu menggunakan konstruktor melainkan membuat panggilan terpisah untuk melakukannya, misalnya
Class* C = new C(); C->SetLogger(logger);
lebih dariClass* C = new C(logger);
Alasan memilih metode ini adalah bahwa logger bukan bagian dasarnya dari kelas tetapi lebih merupakan fitur yang disuntikkan yang digunakan untuk tujuan lain. Menempatkannya di daftar konstruktor membuatnya menjadi persyaratan kelas dan menyiratkan itu adalah bagian dari keadaan logis aktual kelas. Adalah masuk akal untuk mengharapkan, misalnya (dengan sebagian besar kelas meskipun tidak semua), bahwa jika
X != Y
demikianC(X) != C(Y)
tetapi tidak mungkin bahwa Anda akan menguji ketimpangan penebang jika Anda membandingkan terlalu banyak instance dari kelas yang sama.sumber
Perlu disebutkan, sesuatu yang saya belum melihat jawaban lain menyentuh di sini, adalah bahwa dengan membuat logger disuntikkan melalui properti atau statis, membuatnya sulit untuk menguji unit kelas. Misalnya, jika Anda membuat logger Anda disuntikkan melalui properti, Anda sekarang harus menyuntikkan logger itu setiap kali Anda menguji metode yang menggunakan logger. Ini berarti Anda mungkin harus menetapkannya sebagai dependensi konstruktor karena kelas memang membutuhkannya.
Statis cocok untuk masalah yang sama; jika logger tidak berfungsi, maka seluruh kelas Anda gagal (jika kelas Anda menggunakan logger) - meskipun logger belum tentu 'bagian' dari tanggung jawab kelas - meskipun tidak seburuk injeksi properti karena Anda setidaknya tahu bahwa logger selalu "ada" dalam arti tertentu.
Hanya beberapa makanan untuk dipikirkan, terutama jika Anda menggunakan TDD. Menurut pendapat saya, seorang logger seharusnya tidak menjadi bagian dari bagian kelas yang dapat diuji (saat Anda menguji kelas, Anda seharusnya tidak menguji logging Anda juga).
sumber
Saya terlalu malas untuk membagikan objek logger ke setiap instance kelas. Jadi, dalam kode saya, hal-hal semacam ini duduk di bidang statis atau variabel thread-lokal di bidang statis. Yang terakhir ini agak keren dan memungkinkan Anda menggunakan logger yang berbeda untuk setiap utas dan memungkinkan Anda menambahkan metode untuk menghidupkan dan mematikan pencatatan yang melakukan sesuatu yang berarti dan diharapkan dalam aplikasi multi-utas.
sumber