Meskipun pertanyaan umum lingkup saya lebih suka C# seperti aku menyadari bahwa bahasa seperti C++ memiliki semantik yang berbeda mengenai konstruktor eksekusi, manajemen memori, perilaku tidak terdefinisi, dll.
Seseorang bertanya kepada saya sebuah pertanyaan yang menarik bagi saya tidak mudah dijawab.
Mengapa (atau semua?) dianggap sebagai desain yang buruk untuk membiarkan konstruktor dari kelas mulai tidak pernah berakhir loop (yaitu game loop)?
Ada beberapa konsep yang rusak dengan ini:
Dan kemudian ada masalah teknis:
Apakah ada sesuatu yang lebih jelas buruk atau licik dengan pendekatan seperti itu?
Apa tujuan dari sebuah konstruktor? Ia mengembalikan baru dibangun objek. Apa infinite loop lakukan? Hal itu tidak pernah kembali. Bagaimana bisa konstruktor kembali yang baru dibangun objek jika itu doesn't kembali sama sekali? Hal ini dapat't.
Ergo, infinite loop istirahat mendasar kontrak konstruktor: untuk membangun sesuatu.
Apakah ada sesuatu yang lebih jelas buruk atau licik dengan pendekatan seperti itu?
Ya, tentu saja. Hal ini tidak perlu, tak terduga, tidak berguna, unelegant. Melanggar konsep modern desain kelas (kohesi, coupling). Istirahat metode kontrak (konstruktor telah didefinisikan pekerjaan dan bukan hanya beberapa metode random). Hal ini tentunya tidak baik dipertahankan, masa depan programmer akan menghabiskan banyak waktu mencoba untuk memahami apa yang sedang terjadi, dan mencoba untuk menebak alasan mengapa hal itu dilakukan dengan cara itu.
Apa-apa ini adalah "bug" dalam arti bahwa kode anda tidak bekerja. Tapi kemungkinan akan dikenakan besar sekunder biaya (relatif terhadap biaya penulisan kode pada awalnya) dalam jangka panjang dengan membuat code lebih sulit untuk mempertahankan (yaitu, sulit untuk menambahkan tes, sulit untuk kembali, sulit untuk debug, sulit untuk memperpanjang dll.).
Banyak/paling modern perbaikan dalam metode pengembangan perangkat lunak yang dilakukan secara khusus untuk membuat proses yang sebenarnya dari tulisan/pengujian/debug/memelihara perangkat lunak lebih mudah. Semua ini adalah dielakkan oleh hal-hal seperti ini, di mana kode yang ditempatkan secara acak karena itu, "karya".
Sayangnya, anda secara teratur akan bertemu programmer yang benar-benar tahu tentang semua ini. Ia bekerja, yang's ini.
Untuk menyelesaikan dengan analogi (bahasa pemrograman lain, di sini masalah di tangan adalah untuk menghitung 2+2
):
$sum_a = `bash -c "echo $((2+2)) 2>/dev/null"`; # calculate
chomp $sum_a; # remove trailing \n
$sum_a = $sum_a + 0; # force it to be a number in case some non-digit characters managed to sneak in
$sum_b = 2+2;
Apa yang salah dengan pendekatan pertama? Kembali 4 setelah cukup singkat waktu; itu adalah benar. Keberatan (bersama-sama dengan semua alasan yang biasa pengembang dapat memberikan untuk membantah mereka) adalah:
bash
(tapi itu tidak akan pernah berjalan di Windows, Mac atau Android lagian)Anda cukup memberikan alasan dalam pertanyaan anda ke aturan pendekatan ini keluar, tapi pertanyaan yang sebenarnya di sini adalah "Apakah ada sesuatu yang lebih jelas buruk atau licik dengan pendekatan seperti itu?"
Pertama saya meskipun di sini adalah bahwa ini adalah sia-sia. Jika anda konstruktor tidak pernah selesai, tidak ada bagian lain dari program ini dapat mendapatkan referensi untuk constructed objek sehingga apa yang's logika di balik memasukkannya ke dalam constructor bukan cara yang biasa. Kemudian hal itu terjadi kepada saya bahwa satu-satunya perbedaan adalah bahwa dalam loop anda dapat memungkinkan referensi untuk dibangun sebagian ini
melarikan diri dari loop. Saat ini isn't secara ketat terbatas pada situasi ini,'s dijamin bahwa jika anda mengizinkan ini
untuk melarikan diri, referensi tersebut akan selalu menunjuk ke sebuah objek yang tidak sepenuhnya dibangun.
Saya don't tahu apakah semantik sekitar situasi seperti ini yang didefinisikan dengan baik di C# tapi saya berpendapat itu doesn't peduli karena itu's bukan sesuatu yang kebanyakan pengembang akan ingin mencoba untuk menyelidiki.
+1 Untuk sedikit heran, tapi ini adalah konsep sulit untuk mengartikulasikan ke devs baru. Pada tingkat pragmatis, sulit untuk debug pengecualian dibesarkan dalam konstruktor, jika objek gagal untuk menginisialisasi itu tidak akan ada bagi anda untuk memeriksa keadaan atau masuk dari luar yang konstruktor.
Jika anda merasa perlu untuk melakukan hal ini semacam kode pola, silakan gunakan metode statis di kelas bukan.
Konstruktor yang ada untuk memberikan inisialisasi logika ketika sebuah objek yang diturunkan dari definisi kelas. Anda membangun objek ini contoh karena itu sebagai wadah yang merangkum sekumpulan sifat dan fungsi yang ingin anda panggil dari logika aplikasi anda.
Jika anda tidak berniat untuk menggunakan objek yang anda "membangun" lalu apa gunanya instantiating objek di tempat pertama? Setelah beberapa saat(benar) lingkaran dalam constructor secara efektif berarti anda tidak pernah berniat untuk itu untuk menyelesaikan...
C# adalah sangat kaya berorientasi objek bahasa dengan berbagai konstruksi dan paradigma bagi anda untuk mengeksplorasi, mengenal alat-alat dan kapan harus menggunakannya, intinya:
Dalam C# tidak mengeksekusi diperpanjang atau tidak pernah berakhir logika dalam konstruktor karena... ada alternatif yang lebih baik
Mengapa sementara(benar) lingkaran dalam constructor benar-benar buruk?
Yang's tidak buruk sama sekali.
Mengapa (atau semua?) dianggap sebagai desain yang buruk untuk membiarkan konstruktor dari kelas mulai tidak pernah berakhir loop (yaitu game loop)?
Kenapa kau mau melakukan ini? Serius. Kelas yang memiliki fungsi tunggal: konstruktor. Jika semua yang anda inginkan adalah fungsi tunggal, yaitu's mengapa kita memiliki fungsi, tidak konstruktor.
Yang anda sebutkan beberapa alasan yang jelas terhadap hal itu sendiri, tetapi anda meninggalkan keluar sangat terbesar:
Ada yang lebih baik dan pilihan sederhana untuk mencapai hal yang sama.
Jika ada 2 pilihan dan salah satu yang lebih baik, itu doesn't peduli dengan berapa banyak itu lebih baik, anda memilih salah satu yang lebih baik. Kebetulan, yang's mengapa kita don't hampir tidak pernah menggunakan GoTo.
Ada's tidak ada yang inheren buruk tentang hal itu. Namun, apa yang akan menjadi penting adalah pertanyaan mengapa anda memilih untuk menggunakan ini membangun. Apa yang anda dapatkan dengan melakukan ini?
Pertama, saya'm tidak akan berbicara tentang menggunakan while(true)
di sebuah konstruktor. Ada benar-benar tidak ada yang salah dengan menggunakan sintaks dalam constructor. Namun, konsep "memulai permainan lingkaran dalam constructor" adalah salah satu yang dapat menyebabkan beberapa masalah.
It's sangat umum dalam situasi ini memiliki konstruktor hanya membangun objek, dan memiliki fungsi yang menyebut infinite loop. Hal ini memberikan pengguna dari kode anda lebih banyak fleksibilitas. Sebagai contoh dari macam masalah yang dapat muncul adalah bahwa anda membatasi penggunaan objek. Jika seseorang ingin memiliki anggota objek yang "permainan objek" di kelas mereka, mereka harus siap untuk menjalankan seluruh permainan lingkaran dalam konstruktor karena mereka harus membangun objek. Hal ini akan menyebabkan disiksa coding untuk bekerja di sekitar ini. Dalam kasus umum, anda tidak dapat pra-mengalokasikan permainan objek, dan kemudian jalankan nanti. Untuk beberapa program yang's tidak masalah, tapi ada kelas dari program-program di mana anda ingin untuk dapat mengalokasikan segala sesuatu di depan dan kemudian memanggil game loop.
Salah satu aturan praktis dalam pemrograman adalah dengan menggunakan alat sederhana untuk pekerjaan. It's tidak aturan keras dan cepat, tapi itu's sangat berguna. Jika fungsi panggilan sudah cukup, mengapa repot-repot membangun sebuah kelas objek? Jika saya melihat lebih kuat rumit alat yang digunakan, saya berasumsi bahwa pengembang punya alasan untuk itu, dan saya akan mulai mengeksplorasi apa yang macam trik aneh anda mungkin akan melakukan.
Ada kasus di mana hal ini mungkin wajar. Mungkin ada kasus di mana hal ini benar-benar intuitif bagi anda untuk memiliki permainan lingkaran dalam konstruktor. Dalam kasus tersebut, anda menjalankan dengan itu! Misalnya, permainan loop dapat tertanam dalam banyak program yang lebih besar yang membangun kelas-kelas untuk mewujudkan beberapa data. Jika anda memiliki untuk menjalankan game loop untuk menghasilkan data tersebut, itu dapat menjadi sangat wajar untuk menjalankan game loop di sebuah konstruktor. Hanya memperlakukan ini sebagai kasus khusus: itu akan berlaku untuk melakukan hal ini karena yang menyeluruh program membuatnya intuitif untuk selanjutnya pengembang untuk memahami apa yang anda lakukan dan mengapa.
Kesan saya adalah bahwa beberapa konsep-konsep yang terlibat dan mengakibatkan tidak begitu baik bernada pertanyaan.
Konstruktor dari class dapat memulai thread baru yang akan "tidak" end (meskipun saya lebih suka menggunakan sementara(_KeepRunning)
atas while(true)
karena saya dapat mengatur boolean anggota palsu di suatu tempat).
Anda bisa mengekstrak bahwa metode menciptakan dan memulai benang ke dalam fungsi sendiri-sendiri, dalam rangka untuk memisahkan objek pembangunan dan sebenarnya mulai kerja - saya lebih suka cara ini karena saya mendapatkan kontrol yang lebih baik atas akses ke sumber daya.
Anda juga bisa melihat "Aktif Obyek Pola". Pada akhirnya, saya kira pertanyaan itu ditujukan pada ketika memulai thread "Aktif Objek", dan preferensi saya adalah de-coupling konstruksi dan mulai untuk kontrol yang lebih baik.
Objek anda mengingatkan saya dari awal [Tugas](https://msdn.microsoft.com/en-us/library/hh195051(v=vs. 110).aspx). Tugas objek memiliki konstruktor, tapi ada juga sekelompok statis pabrik metode seperti: Tugas.Run
, Task.Start
dan Tugas.Pabrik.StartNew
.
Ini sangat mirip dengan apa yang sedang anda coba untuk lakukan, dan itu's mungkin ini adalah 'convention'. Masalah utama orang-orang tampaknya memiliki adalah bahwa ini penggunaan constructor kejutan mereka. @JörgWMittag kata itu istirahat yang mendasar kontrak, yang aku kira berarti Jörg sangat terkejut. Saya setuju dan punya apa-apa lagi untuk menambahkan untuk itu.
Namun, saya ingin menunjukkan bahwa OP mencoba statis pabrik metode. Kejutan lenyap dan tidak ada dasar kontrak dipertaruhkan di sini. Orang-orang digunakan untuk statis pabrik metode melakukan hal-hal khusus, dan mereka dapat diberi nama sesuai.
Anda dapat memberikan konstruktor yang memungkinkan kontrol berbutir (seperti @Brandin menunjukkan, sesuatu seperti var g = new Game {...}; g.MainLoop();
, yang mengakomodasi pengguna yang don't ingin segera memulai permainan, dan mungkin ingin lulus sekitar terlebih dahulu. Dan anda dapat menulis sesuatu seperti var runningGame = Permainan.StartNew();
untuk membuat awal yang segera mudah.
Tujuan dari constructor adalah untuk, baik, membentuk objek. Sebelum konstruktor telah selesai, maka pada prinsipnya tidak aman untuk penggunaan setiap metode dari objek tersebut. Tentu saja, kita dapat memanggil metode dari objek di dalam konstruktor, tapi kemudian setiap kali kita melakukannya, kita harus memastikan bahwa hal ini berlaku bagi objek yang ada pada saat ini setengah-baken negara.
Dengan secara tidak langsung menempatkan semua logika ke dalam constructor, anda menambahkan lebih banyak beban semacam ini ke diri sendiri. Hal ini menunjukkan bahwa anda tidak merancang perbedaan antara inisialisasi dan gunakan cukup baik.