Kita perlu menerapkan mesin negara sederhana dalam C .
Apakah pernyataan sakelar standar cara terbaik untuk pergi?
Kami memiliki keadaan saat ini (keadaan) dan pemicu untuk transisi.
switch(state)
{
case STATE_1:
state = DoState1(transition);
break;
case STATE_2:
state = DoState2(transition);
break;
}
...
DoState2(int transition)
{
// Do State Work
...
if(transition == FROM_STATE_2) {
// New state when doing STATE 2 -> STATE 2
}
if(transition == FROM_STATE_1) {
// New State when moving STATE 1 -> STATE 2
}
return new_state;
}
Apakah ada cara yang lebih baik untuk mesin status sederhana
EDIT: Untuk C ++, saya pikir perpustakaan Boost Statechart mungkin cara yang tepat. Namun, itu tidak membantu dengan C. Mari kita berkonsentrasi pada kasus penggunaan C.
c
design-patterns
finite-automata
Benoit
sumber
sumber
Jawaban:
Saya lebih suka menggunakan pendekatan berbasis tabel untuk sebagian besar mesin negara:
Ini tentu saja dapat diperluas untuk mendukung beberapa mesin keadaan, dll. Tindakan transisi juga dapat diakomodasi:
Pendekatan berbasis tabel lebih mudah dipelihara dan diperluas dan lebih sederhana untuk dipetakan ke diagram status.
sumber
Anda mungkin telah melihat jawaban saya untuk pertanyaan C lainnya di mana saya menyebutkan FSM! Inilah cara saya melakukannya:
Dengan makro berikut ditentukan
Ini dapat dimodifikasi agar sesuai dengan kasus tertentu. Misalnya, Anda mungkin memiliki file
FSMFILE
yang Anda inginkan untuk menjalankan FSM Anda, sehingga Anda dapat menggabungkan tindakan membaca karakter berikutnya ke dalam makro itu sendiri:sekarang Anda memiliki dua jenis transisi: satu beralih ke status dan membaca karakter baru, yang lain beralih ke status tanpa mengonsumsi input apa pun.
Anda juga dapat mengotomatiskan penanganan EOF dengan sesuatu seperti:
Hal yang baik dari pendekatan ini adalah Anda dapat langsung menerjemahkan diagram status yang Anda gambar menjadi kode yang berfungsi dan, sebaliknya, Anda dapat dengan mudah menggambar diagram status dari kode.
Dalam teknik lain untuk mengimplementasikan FSM, struktur transisi terkubur dalam struktur kontrol (sementara, jika, beralih ...) dan dikendalikan oleh nilai variabel (biasanya
state
variabel) dan mungkin tugas yang kompleks untuk mengaitkan diagram yang bagus dengan a kode berbelit-belit.Saya mempelajari teknik ini dari sebuah artikel yang muncul di majalah besar "Bahasa Komputer" yang sayangnya tidak lagi diterbitkan.
sumber
Saya juga telah menggunakan pendekatan tabel. Namun, ada biaya tambahan. Mengapa menyimpan daftar petunjuk kedua? Sebuah fungsi di C tanpa () adalah pointer const. Jadi Anda bisa melakukan:
Tentu saja tergantung pada faktor ketakutan Anda (yaitu keamanan vs kecepatan), Anda mungkin ingin memeriksa petunjuk yang valid. Untuk mesin status yang lebih besar dari tiga atau lebih status, pendekatan di atas harus lebih sedikit instruksi daripada pendekatan sakelar atau tabel yang setara. Anda bahkan dapat membuat makro sebagai:
Juga, saya merasa dari contoh OP, bahwa ada penyederhanaan yang harus dilakukan ketika memikirkan / mendesain mesin negara. Saya tidak berpikir bahwa keadaan transisi harus digunakan untuk logika. Setiap fungsi keadaan harus dapat menjalankan peran yang diberikan tanpa pengetahuan eksplisit tentang keadaan sebelumnya. Pada dasarnya Anda merancang bagaimana transisi dari keadaan Anda saat ini ke keadaan lain.
Terakhir, jangan memulai desain mesin status berdasarkan batas "fungsional", gunakan subfungsi untuk itu. Sebaliknya bagi negara bagian berdasarkan kapan Anda harus menunggu sesuatu terjadi sebelum Anda dapat melanjutkan. Ini akan membantu meminimalkan berapa kali Anda harus menjalankan mesin status sebelum Anda mendapatkan hasil. Ini bisa menjadi penting saat menulis fungsi I / O, atau penangan interupsi.
Juga, beberapa pro dan kontra dari pernyataan saklar klasik:
Kelebihan:
Kekurangan:
Perhatikan dua atribut yang merupakan pro dan kontra. Saya pikir peralihan memungkinkan kesempatan untuk terlalu banyak berbagi antar negara bagian, dan saling ketergantungan antar negara bagian bisa menjadi tidak terkelola. Namun untuk sejumlah kecil negara bagian, ini mungkin yang paling mudah dibaca dan dipelihara.
sumber
Untuk mesin status sederhana cukup gunakan pernyataan switch dan tipe enum untuk negara Anda. Lakukan transisi Anda di dalam pernyataan sakelar berdasarkan masukan Anda. Dalam program nyata Anda jelas akan mengubah "jika (masukan)" untuk memeriksa titik transisi Anda. Semoga ini membantu.
sumber
Dalam Distilled UML Martin Fowler , dia menyatakan (tidak ada permainan kata-kata) di Bab 10 Diagram Mesin Negara (penekanan milik saya):
Mari kita gunakan contoh sederhana dari status tampilan ponsel:
Sakelar bersarang
Fowler memberikan contoh kode C #, tetapi saya telah menyesuaikannya dengan contoh saya.
Pola negara bagian
Berikut implementasi contoh saya dengan pola GoF State:
Tabel Status
Mengambil inspirasi dari Fowler, inilah tabel untuk contoh saya:
Perbandingan
Sakelar bersarang menyimpan semua logika di satu tempat, tetapi kodenya bisa sulit dibaca ketika ada banyak status dan transisi. Ini mungkin lebih aman dan lebih mudah untuk divalidasi daripada pendekatan lainnya (tanpa polimorfisme atau interpretasi).
Implementasi pola State berpotensi menyebarkan logika ke beberapa kelas terpisah, yang mungkin membuat pemahaman itu secara keseluruhan menjadi masalah. Di sisi lain, kelas kecil mudah dipahami secara terpisah. Desainnya sangat rapuh jika Anda mengubah perilakunya dengan menambahkan atau menghapus transisi, karena keduanya merupakan metode dalam hierarki dan mungkin ada banyak perubahan pada kode. Jika Anda hidup dengan prinsip desain antarmuka kecil, Anda akan melihat pola ini tidak bekerja dengan baik. Namun, jika mesin status stabil, perubahan seperti itu tidak diperlukan.
Pendekatan tabel status memerlukan penulisan semacam penerjemah untuk konten (ini mungkin lebih mudah jika Anda memiliki refleksi dalam bahasa yang Anda gunakan), yang bisa menjadi banyak pekerjaan yang harus dilakukan di depan. Seperti yang ditunjukkan Fowler, jika tabel Anda terpisah dari kode Anda, Anda dapat mengubah perilaku perangkat lunak Anda tanpa kompilasi ulang. Namun, ini memiliki beberapa implikasi keamanan; perangkat lunak berperilaku berdasarkan konten file eksternal.
Edit (tidak benar-benar untuk bahasa C)
Ada juga pendekatan antarmuka yang lancar (alias Bahasa Spesifik Domain internal), yang mungkin difasilitasi oleh bahasa yang memiliki fungsi kelas satu . The Stateless perpustakaan ada dan blog menunjukkan contoh sederhana dengan kode. Sebuah implementasi Java (pra Java8) dibahas. Saya ditunjukkan contoh Python di GitHub juga.
sumber
ada juga grid logika yang lebih dapat dipelihara saat mesin negara semakin besar
sumber
Untuk kasus sederhana, Anda dapat menggunakan metode gaya sakelar. Apa yang saya temukan yang berfungsi dengan baik di masa lalu adalah menangani transisi juga:
Saya tidak tahu apa-apa tentang pustaka dorongan, tetapi jenis pendekatan ini sangat sederhana, tidak memerlukan ketergantungan eksternal, dan mudah diterapkan.
sumber
switch () adalah cara yang andal dan standar untuk mengimplementasikan mesin status di C, tetapi cara ini dapat menurunkan daya rawat jika Anda memiliki banyak status. Metode umum lainnya adalah menggunakan pointer fungsi untuk menyimpan status berikutnya. Contoh sederhana ini mengimplementasikan set / reset flip-flop:
sumber
Saya menemukan implementasi C yang sangat apik dari Moore FSM pada kursus edx.org Sistem Tertanam - Bentuk Dunia UTAustinX - UT.6.02x, bab 10, oleh Jonathan Valvano dan Ramesh Yerraballi ....
sumber
Anda mungkin ingin melihat-lihat perangkat lunak generator FSM libero . Dari bahasa deskripsi negara dan / atau editor diagram status (windows) Anda dapat menghasilkan kode untuk C, C ++, java dan banyak lainnya ... ditambah dokumentasi dan diagram yang bagus. Sumber dan biner dari iMatix
sumber
Artikel ini ini bagus untuk pola negara (meskipun C ++, tidak secara khusus C).
Jika Anda dapat meletakkan tangan Anda pada buku " Pola Desain Kepala Pertama ", penjelasan dan contohnya sangat jelas.
sumber
Salah satu pola favorit saya adalah pola desain negara bagian. Menanggapi atau berperilaku berbeda untuk sekumpulan input yang sama.
Salah satu masalah dengan menggunakan pernyataan sakelar / kasus untuk mesin status adalah saat Anda membuat lebih banyak status, sakelar / kasing menjadi lebih sulit / berat untuk dibaca / dipelihara, mempromosikan kode spaghetti yang tidak terorganisir, dan semakin sulit untuk diubah tanpa merusak sesuatu. Saya menemukan penggunaan pola desain membantu saya mengatur data saya dengan lebih baik, yang merupakan inti dari abstraksi. Alih-alih mendesain kode negara Anda di sekitar negara bagian mana Anda berasal, alih-alih susun kode Anda sehingga ia mencatat keadaan saat Anda memasuki negara bagian baru. Dengan begitu, Anda secara efektif mendapatkan catatan tentang keadaan Anda sebelumnya. Saya menyukai jawaban @ JoshPetit, dan telah mengambil solusinya selangkah lebih maju, diambil langsung dari buku GoF:
stateCtxt.h:
stateCtxt.c:
statehandlers.h:
statehandlers.c:
Untuk sebagian besar Mesin Negara, khususnya. Mesin keadaan terbatas, setiap keadaan akan tahu apa keadaan selanjutnya, dan kriteria untuk transisi ke keadaan berikutnya. Untuk desain status longgar, ini mungkin tidak terjadi, oleh karena itu opsi untuk mengekspos API untuk status transisi. Jika Anda menginginkan lebih banyak abstraksi, setiap penangan status dapat dipisahkan menjadi filenya sendiri, yang setara dengan penangan status konkret di buku GoF. Jika desain Anda sederhana dengan hanya beberapa status, maka stateCtxt.c dan statehandlers.c dapat digabungkan menjadi satu file untuk kesederhanaan.
sumber
Dalam pengalaman saya, menggunakan pernyataan 'switch' adalah cara standar untuk menangani beberapa kemungkinan status. Meskipun saya terkejut bahwa Anda meneruskan nilai transisi ke pemrosesan per status. Saya pikir inti dari mesin negara adalah bahwa setiap negara bagian melakukan satu tindakan. Kemudian tindakan / masukan berikutnya menentukan status baru yang akan ditransisikan. Jadi saya akan mengharapkan setiap fungsi pemrosesan status untuk segera melakukan apa pun yang diperbaiki untuk memasuki status dan kemudian memutuskan apakah transisi diperlukan ke status lain.
sumber
Ada sebuah buku berjudul Practical Statecharts in C / C ++ . Namun, cara yang terlalu berat untuk apa yang kita butuhkan.
sumber
Untuk compiler yang mendukung
__COUNTER__
, Anda bisa menggunakannya untuk state mashine yang sederhana (tapi besar).Keuntungan menggunakan
__COUNTER__
alih-alih nomor kode keras adalah Anda dapat menambahkan status di tengah negara bagian lain, tanpa menomori ulang semuanya. Jika kompilator tidak mendukung__COUNTER__
, dengan cara yang terbatas mungkin untuk digunakan dengan hati-hati__LINE__
sumber
__COUNTER__
menghilangkan kebutuhan untuk menomori ulang, karena precompiler melakukan penomoran selama kompilasi.Anda dapat menggunakan kerangka kerja mesin status UML minimalis di c. https://github.com/kiishor/UML-State-Machine-in-C
Ini mendukung mesin negara hingga dan hierarkis. Ini hanya memiliki 3 API, 2 struktur dan 1 pencacahan.
Mesin Negara diwakili oleh
state_machine_t
struktur. Ini adalah struktur abstrak yang dapat diwariskan untuk membuat mesin negara.Status diwakili oleh penunjuk ke
state_t
struktur dalam kerangka kerja.Jika kerangka dikonfigurasi untuk mesin negara hingga maka
state_t
berisi,Kerangka kerja menyediakan API
dispatch_event
untuk mengirimkan kejadian ke mesin negara dan dua API untuk traversal negara.Untuk detail lebih lanjut tentang cara mengimplementasikan mesin status hierarki, lihat repositori GitHub.
contoh kode
https://github.com/kiishor/UML-State-Machine-in-C/blob/master/demo/simple_state_machine/readme.md
https://github.com/kiishor/UML-State-Machine-in -C / blob / master / demo / simple_state_machine_enhanced / readme.md
sumber
Dalam C ++, pertimbangkan pola Status .
sumber
Pertanyaan Anda mirip dengan "apakah ada pola implementasi Data Base yang khas"? Jawabannya tergantung pada apa yang ingin Anda capai? Jika Anda ingin menerapkan mesin keadaan deterministik yang lebih besar, Anda dapat menggunakan model dan generator mesin keadaan. Contohnya dapat dilihat di www.StateSoft.org - SM Gallery. Janusz Dobrowolski
sumber
Boost memiliki pustaka statechart. http://www.boost.org/doc/libs/1_36_0/libs/statechart/doc/index.html
Namun, saya tidak dapat berbicara tentang kegunaannya. Belum digunakan sendiri (belum)
sumber