Apakah masuk akal untuk membuat blok hanya untuk mengurangi ruang lingkup variabel?


38

Saya sedang menulis sebuah program di Jawa di mana pada satu titik saya perlu memuat kata sandi untuk keystore saya. Hanya untuk bersenang-senang, saya mencoba menjaga kata sandi saya di Jawa sesingkat mungkin dengan melakukan ini:

//Some code
....

KeyManagerFactory keyManager = KeyManagerFactory.getInstance("SunX509");
Keystore keyStore = KeyStore.getInstance("JKS");

{
    char[] password = getPassword();
    keyStore.load(new FileInputStream(keyStoreLocation), password);
    keyManager.init(keyStore, password);
}

...
//Some more code

Sekarang, saya tahu dalam hal ini agak bodoh. Ada banyak hal lain yang bisa saya lakukan, kebanyakan dari mereka sebenarnya lebih baik (saya tidak bisa menggunakan variabel sama sekali).

Namun, saya ingin tahu apakah ada kasus di mana melakukan ini tidak begitu bodoh. Satu-satunya hal lain yang dapat saya pikirkan adalah jika Anda ingin menggunakan kembali nama variabel umum seperti count, atau temp, tetapi konvensi penamaan yang baik dan metode singkat membuatnya tidak mungkin berguna.

Apakah ada kasus di mana menggunakan blok hanya untuk mengurangi ruang lingkup variabel masuk akal?


13
@gnat .... apa? Saya bahkan tidak tahu bagaimana mengedit pertanyaan saya menjadi kurang mirip dengan target dupe itu. Bagian mana dari ini yang membuat Anda percaya pertanyaan-pertanyaan ini sama?
Lord Farquaad

22
Jawaban yang biasa untuk ini adalah bahwa blok anonim Anda harus menjadi metode dengan nama yang signifikan sebagai gantinya, yang memberi Anda dokumentasi otomatis dan mengurangi ruang lingkup yang Anda inginkan. Begitu saja, saya tidak bisa memikirkan situasi di mana mengekstraksi metode tidak lebih baik daripada memasukkan blok telanjang.
Kilian Foth

4
Ada beberapa pertanyaan serupa yang menanyakan hal ini untuk C ++: Apakah praktik yang buruk untuk membuat blok kode? dan Kode Struktur dengan kurung keriting . Mungkin salah satunya berisi jawaban untuk pertanyaan ini, meskipun C ++ dan Java sangat berbeda dalam hal ini.
amon


4
@gnat Mengapa pertanyaan itu bahkan terbuka? Itu salah satu hal terluas yang pernah saya lihat. Apakah ini merupakan upaya pada pertanyaan kanonik?
jpmc26

Jawaban:


34

Pertama, berbicara dengan mekanik yang mendasarinya:

Dalam C ++ scope == Seumur Hidup b / c destructor dipanggil saat keluar dari scope. Selanjutnya, perbedaan penting dalam C / C ++ kita dapat mendeklarasikan objek lokal. Dalam runtime untuk C / C ++ kompiler umumnya akan mengalokasikan bingkai tumpukan untuk metode yang sebesar mungkin diperlukan, di muka, daripada mengalokasikan lebih banyak ruang tumpukan pada entri ke setiap lingkup (yang menyatakan variabel). Jadi, kompiler sedang menciutkan atau meratakan cakupan.

Kompiler C / C ++ dapat menggunakan kembali ruang penyimpanan tumpukan untuk penduduk setempat yang tidak mengalami konflik dalam masa penggunaan (umumnya akan menggunakan analisis kode aktual untuk menentukan ini daripada ruang lingkup, b / c yang lebih akurat daripada ruang lingkup!).

Saya menyebutkan C / C ++ b / c sintaksis Java, yaitu kurung kurawal dan pelingkupan, setidaknya sebagian berasal dari keluarga itu. Dan juga karena C ++ muncul dalam komentar pertanyaan.

Sebaliknya, tidak mungkin untuk memiliki objek lokal di Jawa: semua objek adalah objek tumpukan, dan semua lokal / formal adalah variabel referensi atau tipe primitif (btw, hal yang sama berlaku untuk statika).

Selanjutnya, dalam lingkup dan masa hidup Jawa tidak sepenuhnya disamakan: berada di / keluar dari ruang lingkup sebagian besar adalah konsep waktu kompilasi pergi ke aksesibilitas dan konflik nama; tidak ada yang benar-benar terjadi di Java pada exit scope terkait dengan pembersihan variabel. Pengumpulan sampah Jawa menentukan (titik akhir) objek seumur hidup.

Juga mekanisme bytecode Java (output dari Java compiler) cenderung untuk mempromosikan variabel-variabel pengguna yang dideklarasikan dalam lingkup terbatas ke tingkat atas metode, karena tidak ada fitur lingkup pada tingkat bytecode (ini mirip dengan penanganan C / C ++ dari tumpukan). Paling-paling kompiler dapat menggunakan kembali slot variabel lokal, tetapi (tidak seperti C / C ++) hanya jika jenisnya sama.

(Padahal, untuk memastikan compiler JIT yang mendasarinya dalam runtime dapat menggunakan kembali ruang penyimpanan stack yang sama untuk dua penduduk lokal yang diketik berbeda (dan ditempatkan berbeda), dengan analisis yang memadai dari bytecode.)

Berbicara untuk keuntungan programmer, saya akan cenderung setuju dengan yang lain bahwa metode (pribadi) adalah konstruk yang lebih baik bahkan jika digunakan hanya sekali.

Namun, tidak ada yang salah dengan menggunakannya untuk mendekripsi nama.

Saya telah melakukan ini dalam keadaan yang jarang terjadi ketika membuat metode individual adalah beban. Sebagai contoh, ketika menulis penerjemah menggunakan switchpernyataan besar dalam satu lingkaran, saya mungkin (tergantung pada faktor-faktor) memperkenalkan blok terpisah untuk masing-masing caseuntuk menjaga masing-masing kasus lebih terpisah satu sama lain, daripada membuat setiap kasus metode yang berbeda (masing-masing dari yang hanya dipanggil sekali).

(Catat bahwa sebagai kode dalam blok, masing-masing case memiliki akses ke pernyataan "break;" dan "continue;" mengenai loop penutup, sedangkan sebagai metode akan membutuhkan boolean yang kembali dan penggunaan kondisional pemanggil untuk mendapatkan akses ke aliran kontrol ini pernyataan.)


Jawaban yang sangat menarik (+1)! Namun satu pelengkap untuk bagian C ++. Jika kata sandi adalah string dalam sebuah blok, objek string akan mengalokasikan ruang di suatu tempat di toko gratis untuk bagian ukuran variabel. Saat meninggalkan blok, string akan dimusnahkan, yang mengakibatkan deallokasi bagian variabel. Tetapi karena tidak ada di stack, tidak ada yang menjamin bahwa itu akan segera ditimpa. Jadi, lebih baik kelola kerahasiaan dengan menimpa masing-masing karakternya sebelum string dihancurkan ;-)
Christophe

1
@ErikEidt Saya mencoba untuk menarik perhatian pada masalah berbicara tentang "C / C ++" seolah-olah itu sebenarnya "sesuatu", tetapi tidak: "Dalam runtime untuk C / C ++ kompiler umumnya akan mengalokasikan bingkai tumpukan untuk metode yang sebesar mungkin diperlukan " tetapi C tidak memiliki metode sama sekali. Ini memiliki fungsi. Ini berbeda, terutama di C ++.
tchrist

7
" Sebaliknya, tidak mungkin untuk memiliki objek lokal di Jawa: semua objek adalah objek tumpukan, dan semua lokal / formal adalah variabel referensi atau tipe primitif (btw, hal yang sama berlaku untuk statika). " - Perhatikan bahwa ini adalah tidak sepenuhnya benar, terutama tidak untuk metode variabel lokal. Analisis melarikan diri dapat mengalokasikan objek ke tumpukan.
Boris the Spider

1
Paling-paling kompiler dapat menggunakan kembali slot variabel lokal, tetapi (tidak seperti C / C ++) hanya jika jenisnya sama. ”Itu salah. Pada level bytecode, variabel lokal dapat ditugaskan dan dipindahkan dengan apa pun yang Anda inginkan, satu-satunya kendala adalah bahwa penggunaan selanjutnya kompatibel dengan jenis item yang ditugaskan terbaru. Menggunakan kembali slot variabel lokal adalah norma, misalnya dengan { int x = 42; String s="blah"; } { long y = 0; }, longvariabel akan menggunakan kembali slot kedua variabel, xdan sdengan semua kompiler yang biasa digunakan ( javacdan ecj).
Holger

1
@Boris the Spider: itu pernyataan sehari-hari yang sering diulang yang tidak benar-benar cocok dengan apa yang terjadi. Escape Analysis dapat mengaktifkan Skalarisasi, yang merupakan penguraian bidang objek menjadi variabel, yang kemudian akan dioptimalkan lebih lanjut. Beberapa dari mereka mungkin dihilangkan sebagai tidak terpakai, yang lain mungkin dilipat dengan variabel sumber yang digunakan untuk menginisialisasi mereka, yang lain dipetakan ke register CPU. Hasilnya jarang cocok dengan apa yang mungkin dibayangkan orang ketika mengatakan "dialokasikan pada tumpukan".
Holger

27

Menurut pendapat saya akan lebih jelas untuk menarik blok ke metode sendiri. Jika Anda meninggalkan blok ini, saya berharap untuk melihat komentar yang menjelaskan mengapa Anda meletakkan blok di tempat pertama. Pada saat itu terasa lebih bersih untuk memiliki pemanggilan metode initializeKeyManager()yang membuat variabel kata sandi terbatas pada ruang lingkup metode dan menunjukkan maksud Anda dengan blok kode.


2
Saya pikir jawaban Anda dilewati oleh penggunaan kunci utama, ini merupakan langkah perantara selama refactor. Ini berguna untuk membatasi ruang lingkup dan mengetahui kode Anda masih berfungsi sesaat sebelum mengekstraksi suatu metode.
RubberDuck

16
@RubberDuck benar, tetapi dalam hal ini kita semua seharusnya tidak pernah melihatnya sehingga tidak masalah apa yang kita pikirkan. Apa yang didapat oleh seorang pembuat kode dewasa dan penyusun persetujuan dalam privasi bilik mereka sendiri bukan urusan orang lain.
candied_orange

@candied_orange Saya khawatir saya tidak mengerti :(
Mau

@doubleOrt Maksud saya langkah-langkah refactoring menengah adalah nyata dan perlu tetapi tentu saja tidak perlu diabadikan dalam kontrol sumber di mana semua orang dapat melihatnya.
Selesaikan

@candied_orange Oh, mengira Anda sedang berdebat dan tidak memperpanjang argumen RubberDuck.
doubleOrt

17

Mereka dapat berguna di Rust, dengan aturan peminjaman yang ketat. Dan umumnya, dalam bahasa fungsional, di mana blok itu mengembalikan nilai. Tetapi dalam bahasa seperti Jawa? Meskipun ide itu tampak elegan, dalam praktiknya jarang digunakan sehingga kebingungan dari melihatnya akan mengecilkan potensi kejelasan membatasi ruang lingkup variabel.

Ada satu kasus di mana saya menemukan ini berguna - dalam sebuah switchpernyataan! Terkadang Anda ingin mendeklarasikan variabel dalam case:

switch (op) {
    case ADD:
        int result = a + b;
        System.out.printf("%s + %s = %s\n", a, b, result);
        break;
    case SUB:
        int result = a - b;
        System.out.printf("%s - %s = %s\n", a, b, result);
        break;
}

Namun, ini akan gagal:

error: variable result is already defined in method main(String[])
            int result = a - b;

switch pernyataan itu aneh - itu adalah pernyataan kontrol, tetapi karena kegagalan mereka, mereka tidak memperkenalkan cakupan.

Jadi - Anda bisa menggunakan blok untuk membuat lingkup sendiri:

switch (op) {
    case ADD: {
        int result = a + b;
        System.out.printf("%s + %s = %s\n", a, b, result);
    } break;
    case SUB: {
        int result = a - b;
        System.out.printf("%s - %s = %s\n", a, b, result);
    } break;
}

6
  • Kasus umum:

Apakah ada kasus di mana menggunakan blok hanya untuk mengurangi ruang lingkup variabel masuk akal?

Pada umumnya dianggap praktik yang baik untuk membuat metode tetap singkat. Mengurangi ruang lingkup beberapa variabel bisa menjadi tanda bahwa metode Anda cukup panjang, cukup sehingga Anda berpikir ruang lingkup variabel perlu dikurangi. Dalam hal ini, mungkin perlu membuat metode terpisah untuk bagian kode tersebut.

Kasus-kasus yang saya temukan bermasalah adalah ketika bagian kode menggunakan lebih dari beberapa argumen. Ada situasi di mana Anda bisa berakhir dengan metode kecil yang masing-masing mengambil banyak parameter (atau perlu solusi untuk mensimulasikan pengembalian beberapa nilai). Solusi untuk masalah khusus itu adalah membuat kelas lain yang tetap menggunakan berbagai variabel yang Anda gunakan, dan mengimplementasikan mengimplementasikan semua langkah yang ada dalam pikiran Anda dalam metode yang relatif singkat: ini adalah kasus penggunaan khas untuk menggunakan pola Builder .

Yang mengatakan, semua pedoman pengkodean ini kadang-kadang dapat diterapkan secara longgar. Kadang-kadang ada kasus aneh, di mana kode bisa lebih mudah dibaca jika Anda menyimpannya dalam metode yang sedikit lebih lama, daripada membaginya menjadi sub-metode kecil (atau pola pembangun). Biasanya, ini berfungsi untuk masalah yang berukuran sedang, cukup linier, dan di mana terlalu banyak pemisahan sebenarnya menghambat keterbacaan (terutama jika Anda perlu melompat di antara terlalu banyak metode untuk memahami apa yang dilakukan kode).

Ini bisa masuk akal, tetapi sangat jarang.

  • Kasus penggunaan Anda:

Ini kodenya:

KeyManagerFactory keyManager = KeyManagerFactory.getInstance("SunX509");
Keystore keyStore = KeyStore.getInstance("JKS");

{
    char[] password = getPassword();
    keyStore.load(new FileInputStream(keyStoreLocation), password);
    keyManager.init(keyStore, password);
}

Anda sedang membuat FileInputStream, tetapi Anda tidak pernah menutupnya.

Salah satu cara untuk memecahkan masalah ini adalah dengan menggunakan pernyataan coba-dengan-sumber daya . Ini cakupan InputStream, dan Anda juga dapat menggunakan blok ini untuk mengurangi cakupan variabel lain jika Anda inginkan (karena alasan, karena baris ini terkait):

KeyManagerFactory keyManager = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
Keystore keyStore = KeyStore.getInstance("JKS");

try (InputStream fis = new FileInputStream(keyStoreLocation)) {
    char[] password = getPassword();
    keyStore.load(fis, password);
    keyManager.init(keyStore, password);
}

(Ngomong-ngomong juga sering lebih baik digunakan getDefaultAlgorithm()daripada SunX509, omong-omong.)

Selain itu, sementara saran untuk memisahkan potongan kode menjadi metode yang terpisah umumnya baik. Jarang sepadan jika hanya untuk 3 baris (jika ada, itu adalah kasus di mana membuat metode terpisah menghambat keterbacaan).


"Mengurangi ruang lingkup beberapa variabel bisa menjadi tanda bahwa metode Anda cukup panjang" - Ini bisa menjadi tanda tetapi juga bisa dan IMHO harus digunakan untuk mendokumentasikan berapa lama nilai variabel lokal digunakan. Bahkan, untuk bahasa yang tidak mendukung cakupan bersarang (misalnya Python) saya akan menghargai jika komentar kode yang sesuai menyatakan "akhir hidup" dari suatu variabel. Jika variabel yang sama digunakan kembali nanti akan mudah untuk mengetahui apakah harus (atau seharusnya) diinisialisasi dengan nilai baru di suatu tempat sebelumnya (tetapi setelah komentar "akhir hidup").
Jonny Dee

2

Menurut pendapat saya yang sederhana, itu umumnya sesuatu untuk dihindari sebagian besar untuk kode produksi karena Anda umumnya tidak tergoda untuk melakukannya kecuali dalam fungsi sporadis yang melakukan tugas yang berbeda. Saya cenderung melakukannya dalam beberapa memo kode yang digunakan untuk menguji sesuatu, tetapi tidak menemukan godaan untuk melakukannya dalam kode produksi di mana saya sudah memikirkan terlebih dahulu apa yang harus dilakukan masing-masing fungsi, sejak itu fungsi secara alami akan memiliki sangat ruang lingkup terbatas sehubungan dengan negara setempat.

Saya tidak pernah benar-benar melihat contoh blok anonim yang digunakan seperti ini (tidak melibatkan persyaratan, tryblok untuk transaksi, dll) untuk mengurangi ruang lingkup dengan cara yang bermakna dalam fungsi yang tidak memunculkan pertanyaan mengapa tidak bisa dibagi lebih jauh menjadi fungsi-fungsi yang lebih sederhana dengan lingkup yang diperkecil jika sebenarnya benar-benar diuntungkan dari sudut pandang SE asli dari blok anonim. Biasanya kode eklektik yang melakukan banyak hal yang terkait atau sangat tidak terkait di mana kita paling tergoda untuk mencapai ini.

Sebagai contoh, jika Anda mencoba melakukan ini untuk menggunakan kembali variabel bernama count, maka itu menyarankan Anda menghitung dua hal yang berbeda. Jika nama variabel akan sesingkat count, maka masuk akal bagi saya untuk mengikatnya dengan konteks fungsi, yang berpotensi hanya menghitung satu jenis hal. Kemudian Anda dapat langsung melihat nama fungsi dan / atau dokumentasi, melihat count, dan langsung tahu apa artinya dalam konteks fungsi apa yang dilakukan tanpa menganalisis semua kode. Saya tidak sering menemukan argumen yang baik untuk fungsi menghitung dua hal yang berbeda menggunakan kembali nama variabel yang sama dengan cara yang membuat lingkup / blok anonim begitu menarik dibandingkan dengan alternatif. Itu tidak menyarankan bahwa semua fungsi harus menghitung hanya satu hal. SAYA'manfaat rekayasa untuk fungsi menggunakan kembali nama variabel yang sama untuk menghitung dua hal atau lebih dan menggunakan blok anonim untuk membatasi ruang lingkup setiap hitungan individu. Jika fungsi ini sederhana dan jelas, ini bukan akhir dunia untuk memiliki dua variabel jumlah yang dinamai berbeda dengan yang pertama mungkin memiliki beberapa garis visibilitas ruang lingkup lebih dari yang dibutuhkan secara ideal. Fungsi seperti itu umumnya bukan sumber kesalahan yang kurang memiliki blok anonim seperti itu untuk mengurangi ruang lingkup minimum variabel lokalnya lebih jauh.

Bukan Saran untuk Metode Berlebihan

Ini bukan untuk menyarankan Anda secara paksa membuat metode hanya untuk mengurangi ruang lingkup. Itu bisa dibilang sama buruk atau lebih buruknya, dan apa yang saya sarankan tidak harus menyerukan perlunya metode "pembantu" pribadi yang canggung lebih daripada kebutuhan akan lingkup anonim. Itu berpikir terlalu banyak tentang kode seperti sekarang dan bagaimana mengurangi ruang lingkup variabel daripada berpikir tentang bagaimana memecahkan masalah secara konseptual pada tingkat antarmuka dengan cara yang menghasilkan bersih, visibilitas singkat dari fungsi lokal secara alami tanpa blok penyangga yang dalam. dan 6+ level indentasi. Saya setuju dengan Bruno bahwa Anda dapat menghalangi pembacaan kode dengan secara paksa mendorong 3 baris kode ke dalam suatu fungsi, tetapi itu dimulai dengan asumsi bahwa Anda mengembangkan fungsi yang Anda buat berdasarkan implementasi yang ada, daripada mendesain fungsi tanpa terlibat dalam implementasi. Jika Anda melakukannya dengan cara yang terakhir, saya telah menemukan sedikit kebutuhan untuk blok anonim yang tidak melayani tujuan selain mengurangi ruang lingkup variabel dalam metode yang diberikan kecuali Anda mencoba dengan penuh semangat untuk mengurangi ruang lingkup variabel dengan hanya beberapa baris kode berbahaya. di mana pengenalan eksotis dari blok anonim ini bisa dibilang menyumbang overhead intelektual sebanyak yang mereka keluarkan.

Mencoba Mengurangi Lingkup Minimum Lebih Jauh

Jika mengurangi lingkup variabel lokal ke minimum absolut bermanfaat, maka harus ada penerimaan luas kode seperti ini:

ImageIO.write(new Robot("borg").createScreenCapture(new Rectangle(Toolkit.getDefaultToolkit().getScreenSize())), "png", new File(Db.getUserId(User.handle()).toString()));

... karena hal itu menyebabkan visibilitas minimum negara dengan bahkan tidak membuat variabel untuk merujuk mereka di tempat pertama. Saya tidak ingin tampil sebagai dogmatis, tetapi saya benar-benar berpikir solusi pragmatis adalah menghindari blok anonim jika mungkin seperti halnya menghindari garis kode yang mengerikan di atas, dan jika mereka tampaknya sangat diperlukan dalam konteks produksi dari perspektif kebenaran dan menjaga invarian dalam suatu fungsi, maka saya pasti berpikir bagaimana Anda mengatur kode Anda ke dalam fungsi dan merancang antarmuka Anda perlu diperiksa ulang. Tentu saja jika metode Anda panjang 400 baris dan ruang lingkup variabel lebih dari 300 baris kode, itu bisa menjadi masalah teknik asli, tetapi itu tidak selalu masalah untuk dipecahkan dengan blok anonim.

Jika tidak ada yang lain, memanfaatkan blok anonim di semua tempat itu eksotis, bukan idiomatik, dan kode eksotis membawa risiko dibenci oleh orang lain, jika bukan diri Anda sendiri, bertahun-tahun kemudian.

Kegunaan Praktis Mengurangi Lingkup

Kegunaan utama mengurangi ruang lingkup variabel adalah untuk memungkinkan Anda mendapatkan manajemen negara yang benar dan menjaganya tetap benar dan memungkinkan Anda untuk dengan mudah bernalar tentang apa yang dilakukan porsi basis kode tertentu - untuk dapat mempertahankan invarian konseptual. Jika manajemen keadaan lokal fungsi tunggal sangat kompleks sehingga Anda harus secara paksa mengurangi ruang lingkup dengan blok anonim dalam kode yang tidak dimaksudkan untuk diselesaikan dan bagus, sekali lagi, itu pertanda bagi saya bahwa fungsi itu sendiri perlu diperiksa ulang . Jika Anda mengalami kesulitan dalam penalaran tentang pengelolaan variabel negara dalam lingkup fungsi lokal, bayangkan kesulitan penalaran tentang variabel pribadi yang dapat diakses oleh setiap metode dari seluruh kelas. Kami tidak dapat menggunakan blok anonim untuk mengurangi visibilitasnya. Bagi saya, memulainya dengan penerimaan bahwa variabel akan cenderung memiliki cakupan yang sedikit lebih luas daripada yang seharusnya mereka miliki dalam banyak bahasa, asalkan tidak sampai pada titik di mana Anda akan kesulitan mempertahankan invarian. Itu bukan sesuatu yang harus dipecahkan dengan blok anonim seperti yang saya lihat sebagai menerima dari sudut pandang pragmatis.


Sebagai peringatan terakhir, seperti yang saya sebutkan saya masih menggunakan blok anonim dari waktu ke waktu, sering dalam metode titik masuk utama untuk kode memo. Orang lain menyebutkannya sebagai alat refactoring dan saya pikir itu baik-baik saja, karena hasilnya adalah perantara dan dimaksudkan untuk lebih lanjut di-refactored, bukan kode yang difinalisasi. Saya tidak mengabaikan manfaatnya sepenuhnya, tetapi jika Anda mencoba untuk menulis kode yang diterima secara luas, diuji dengan baik, dan benar, saya hampir tidak melihat perlunya blok anonim. Terobsesi dalam menggunakannya dapat mengalihkan fokus dari mendesain fungsi yang lebih jelas dengan blok kecil alami.

2

Apakah ada kasus di mana menggunakan blok hanya untuk mengurangi ruang lingkup variabel masuk akal?

Saya pikir motivasi adalah alasan yang cukup untuk memperkenalkan penghambat, ya.

Seperti dicatat Casey, blok adalah "bau kode" yang menunjukkan Anda mungkin lebih baik mengekstraksi blok ke dalam suatu fungsi. Tapi kamu mungkin tidak.

John Carmark menulis memo tentang kode inline pada 2007. Ringkasan kesimpulannya

  • Jika suatu fungsi hanya dipanggil dari satu tempat, pertimbangkan untuk menggarisbawahinya.
  • Jika suatu fungsi dipanggil dari beberapa tempat, lihat apakah mungkin untuk mengatur agar pekerjaan dilakukan di satu tempat, mungkin dengan bendera, dan sebariskan itu.
  • Jika ada beberapa versi fungsi, pertimbangkan membuat fungsi tunggal dengan lebih banyak, mungkin standar, parameter.
  • Jika pekerjaan itu hampir sepenuhnya berfungsi, dengan sedikit referensi tentang keadaan global, cobalah membuatnya berfungsi sepenuhnya.

Jadi pikirkan , buat pilihan dengan tujuan, dan (opsional) tinggalkan bukti yang menggambarkan motivasi Anda untuk pilihan yang Anda buat.


1

Pendapat saya mungkin kontroversial, tapi ya, saya pikir pasti ada situasi di mana saya akan menggunakan gaya seperti ini. Namun, "hanya untuk mengurangi ruang lingkup variabel" bukan argumen yang valid, karena itulah yang sudah Anda lakukan. Dan melakukan sesuatu hanya untuk melakukannya bukan alasan yang sah. Perhatikan juga bahwa penjelasan ini tidak memiliki arti jika tim Anda telah memutuskan apakah sintaksis semacam ini konvensional atau tidak.

Saya terutama seorang programmer C #, tetapi saya telah mendengarnya di Jawa, mengembalikan kata sandi sebagai char[] yang memungkinkan Anda untuk mengurangi waktu kata sandi akan tinggal di memori. Dalam contoh ini, itu tidak akan membantu, karena pengumpul sampah diizinkan untuk mengumpulkan array dari saat itu tidak digunakan, jadi tidak masalah jika kata sandi meninggalkan ruang lingkup. Saya tidak berdebat apakah layak untuk menghapus array setelah Anda selesai dengan itu, tetapi dalam kasus ini, jika Anda ingin melakukannya, pelingkupan variabel masuk akal:

{
    char[] password = getPassword();
    try{
        keyStore.load(new FileInputStream(keyStoreLocation), password);
        keyManager.init(keyStore, password);
    }finally{
        Arrays.fill(password, '\0');
    }
}

Ini sangat mirip dengan coba-dengan-sumber daya , karena ini lingkup sumber daya dan melakukan finalisasi setelah Anda selesai. Sekali lagi harap dicatat bahwa saya tidak berdebat untuk menangani kata sandi dengan cara ini, hanya saja jika Anda memutuskan untuk melakukannya, gaya ini masuk akal.

Alasan untuk ini adalah bahwa variabel tidak lagi valid. Anda telah membuatnya, menggunakannya, dan membatalkan statusnya untuk tidak mengandung informasi yang berarti. Tidak masuk akal untuk menggunakan variabel setelah blok ini, jadi masuk akal untuk lingkup itu.

Contoh lain yang bisa saya pikirkan adalah ketika Anda memiliki dua variabel yang memiliki nama dan makna yang serupa, tetapi Anda bekerja dengan satu dan kemudian dengan yang lain, dan Anda ingin memisahkannya. Saya telah menulis kode ini dalam C #:

{
    MethodBuilder m_ToString = tb.DefineMethod("ToString", MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Final, typeofString, Type.EmptyTypes);
    var il = m_ToString.GetILGenerator();
    il.Emit(OpCodes.Ldstr, templateType.ToString()+":"+staticType.ToString());
    il.Emit(OpCodes.Ret);
    tb.DefineMethodOverride(m_ToString, m_Object_ToString);
}
{
    PropertyBuilder p_Class = tb.DefineProperty("Class", PropertyAttributes.None, typeofType, Type.EmptyTypes);
    MethodBuilder m_get_Class = tb.DefineMethod("get_Class", MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Final, typeofType, Type.EmptyTypes);
    var il = m_get_Class.GetILGenerator();
    il.Emit(OpCodes.Ldtoken, staticType);
    il.Emit(OpCodes.Call, m_Type_GetTypeFromHandle);
    il.Emit(OpCodes.Ret);
    p_Class.SetGetMethod(m_get_Class);
    tb.DefineMethodOverride(m_get_Class, m_IPattern_get_Class);
}

Anda dapat berpendapat bahwa saya dapat mendeklarasikan ILGenerator il;di bagian atas metode, tetapi saya juga tidak ingin menggunakan kembali variabel untuk objek yang berbeda (pendekatan yang agak fungsional). Dalam hal ini, blok memudahkan untuk memisahkan pekerjaan yang dilakukan, baik secara sintaksis maupun visual. Ia juga memberi tahu bahwa setelah blok, saya selesai ildan tidak ada yang mengaksesnya.

Argumen terhadap contoh ini menggunakan metode. Mungkin ya, tetapi dalam kasus ini, kodenya tidak terlalu panjang, dan memisahkannya ke dalam metode yang berbeda juga perlu untuk meneruskan semua variabel yang digunakan dalam kode.

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.