Menggabungkan metode template dengan strategi


14

Tugas dalam kelas rekayasa perangkat lunak saya adalah merancang aplikasi yang dapat memainkan berbagai bentuk permainan tertentu. Gim yang dimaksud adalah Mancala, beberapa gim ini disebut Wari atau Kalah. Game-game ini berbeda dalam beberapa aspek, tetapi untuk pertanyaan saya, penting untuk mengetahui bahwa game-game tersebut dapat berbeda sebagai berikut:

  • Cara penanganan suatu langkah ditangani
  • Cara akhir permainan ditentukan
  • Cara penentuan pemenang

Hal pertama yang muncul di benak saya untuk mendesain ini adalah menggunakan pola strategi, saya memiliki variasi dalam algoritma (aturan sebenarnya dari permainan). Desainnya bisa seperti ini: masukkan deskripsi gambar di sini

Saya kemudian berpikir dalam permainan Mancala dan Wari cara pemenang ditentukan persis sama dan kode akan diduplikasi. Saya tidak berpikir ini dengan definisi pelanggaran 'satu aturan, satu tempat' atau prinsip KERING melihat perubahan dalam aturan untuk Mancala tidak secara otomatis berarti bahwa aturan harus diubah di Wari juga. Namun demikian dari umpan balik yang saya dapatkan dari profesor saya, saya mendapat kesan untuk menemukan desain yang berbeda.

Saya kemudian datang dengan ini: masukkan deskripsi gambar di sini

Setiap permainan (Mancala, Wari, Kalah, ...) hanya akan memiliki atribut dari jenis antarmuka masing-masing aturan, yaitu WinnerDeterminerdan jika ada versi Mancala 2.0 yang sama dengan Mancala 1.0 kecuali untuk bagaimana pemenang ditentukan itu hanya bisa gunakan versi Mancala.

Saya pikir penerapan aturan-aturan ini sebagai pola strategi tentu valid. Tapi masalah sebenarnya datang ketika saya ingin mendesainnya lebih lanjut.

Dalam membaca tentang pola metode templat saya langsung berpikir itu bisa diterapkan untuk masalah ini. Tindakan yang dilakukan saat pengguna bergerak selalu sama, dan dalam urutan yang sama, yaitu:

  • deposit batu dalam lubang (ini sama untuk semua game, jadi akan diterapkan dalam metode templat itu sendiri)
  • tentukan hasil dari langkah tersebut
  • tentukan apakah permainan telah selesai karena langkah sebelumnya
  • jika permainan telah selesai, tentukan siapa yang telah menang

Ketiga langkah terakhir semuanya ada dalam pola strategi saya yang dijelaskan di atas. Saya mengalami banyak kesulitan menggabungkan keduanya. Salah satu solusi yang mungkin saya temukan adalah meninggalkan pola strategi dan melakukan yang berikut: masukkan deskripsi gambar di sini

Saya tidak benar-benar melihat perbedaan desain antara pola strategi dan ini? Tetapi saya yakin saya perlu menggunakan metode templat (walaupun saya yakin harus menggunakan pola strategi).

Saya juga tidak dapat menentukan siapa yang akan bertanggung jawab untuk membuat TurnTemplateobjek, sedangkan dengan pola strategi saya merasa memiliki keluarga objek (tiga aturan) yang saya dapat dengan mudah membuat menggunakan pola pabrik abstrak. Saya kemudian akan memiliki MancalaRuleFactory, WariRuleFactory, dll dan mereka akan menciptakan contoh yang benar dari aturan dan tangan saya kembali sebuah RuleSetobjek.

Katakanlah saya menggunakan strategi + pola pabrik abstrak dan saya memiliki RuleSetobjek yang memiliki algoritma untuk tiga aturan di dalamnya. Satu - satunya cara saya merasa saya masih dapat menggunakan pola metode templat dengan ini adalah meneruskan RuleSetobjek ini ke saya TurnTemplate. 'Masalah' yang muncul kemudian adalah bahwa saya tidak akan pernah membutuhkan implementasi konkret saya TurnTemplate, kelas-kelas ini akan menjadi usang. Dalam metode saya yang dilindungi di TurnTemplatesaya hanya bisa menelepon ruleSet.determineWinner(). Sebagai konsekuensinya, TurnTemplatekelas tidak lagi abstrak tetapi harus menjadi konkret, apakah kemudian masih menjadi pola metode templat?

Ringkasnya, apakah saya berpikir dengan cara yang benar atau apakah saya kehilangan sesuatu yang mudah? Jika saya berada di jalur yang benar, bagaimana cara menggabungkan pola strategi dan pola metode templat?


1
Saya akan mengatakan bahwa pemikiran Anda cukup tepat. Jika umpan balik yang Anda dapatkan dari profesor Anda tidak memvalidasi itu, minta dia untuk menunjukkan kekurangannya, atau berikan petunjuk tentang apa yang dia cari dalam jawabannya. Berhentilah mencoba membaca pikiran. Dengan asumsi hal-hal tentang apa yang diinginkan profesor Anda (dan kemudian pengguna Anda) mungkin adalah yang terburuk yang dapat Anda lakukan.
Marjan Venema

" ... dalam permainan Mancala dan Wari cara pemenang ditentukan adalah persis sama dan kodenya akan digandakan. " Mengapa itu menyiratkan bahwa kodenya digandakan? Biarkan saja kedua kelas memanggil fungsi yang sama.
D Drmmr

Jawaban:


6

Setelah melihat desain Anda, iterasi pertama dan ketiga Anda tampaknya menjadi desain yang lebih elegan. Namun, Anda menyebutkan bahwa Anda seorang mahasiswa dan profesor Anda memberi Anda umpan balik. Tanpa tahu persis apa tugas Anda atau tujuan kelas atau informasi lebih lanjut tentang apa yang disarankan profesor Anda, saya akan mengambil apa pun yang saya katakan di bawah ini dengan sebutir garam.

Dalam desain pertama Anda, Anda menyatakan bahwa Anda RuleInterfaceadalah sebuah antarmuka yang menentukan cara menangani giliran setiap pemain, bagaimana menentukan apakah permainan sudah berakhir, dan bagaimana menentukan pemenang setelah permainan berakhir. Sepertinya itu antarmuka yang valid untuk keluarga gim yang mengalami variasi. Namun, tergantung pada gimnya, Anda mungkin memiliki kode duplikat. Saya setuju bahwa fleksibilitas untuk mengubah aturan satu permainan adalah hal yang baik, tetapi saya juga berpendapat bahwa duplikasi kode mengerikan untuk cacat. Jika Anda menyalin / menempelkan kode yang rusak antara implementasi dan satu memiliki bug di dalamnya, Anda sekarang memiliki beberapa bug yang perlu diperbaiki di lokasi yang berbeda. Jika Anda menulis ulang implementasi di waktu yang berbeda, Anda bisa memperkenalkan cacat di lokasi yang berbeda. Tak satu pun dari mereka yang diinginkan.

Desain kedua Anda tampaknya agak rumit, dengan pohon warisan yang dalam. Setidaknya, ini lebih dalam daripada yang saya harapkan untuk memecahkan masalah jenis ini. Anda juga mulai memecah detail implementasi ke kelas lain. Pada akhirnya, Anda memodelkan dan mengimplementasikan game. Ini mungkin merupakan pendekatan yang menarik jika Anda diminta mencampur dan mencocokkan aturan Anda untuk menentukan hasil langkah, akhir pertandingan, dan pemenang, yang tampaknya tidak berada dalam persyaratan yang Anda sebutkan . Game Anda adalah seperangkat aturan yang didefinisikan dengan baik, dan saya akan mencoba merangkum game sebanyak yang saya bisa menjadi entitas yang terpisah.

Desain ketiga Anda adalah salah satu yang paling saya sukai. Satu-satunya kekhawatiran saya adalah bahwa itu tidak pada tingkat abstraksi yang tepat. Saat ini, Anda tampaknya menjadi pemodelan giliran. Saya akan merekomendasikan mempertimbangkan merancang game. Pertimbangkan bahwa Anda memiliki pemain yang bergerak di semacam papan, menggunakan batu. Game Anda membutuhkan aktor-aktor ini untuk hadir. Dari sana, algoritma Anda tidak doTurn()tetapi playGame(), yang bergerak dari langkah awal ke langkah terakhir, setelah itu berakhir. Setelah setiap gerakan pemain, itu akan menyesuaikan kondisi permainan, menentukan apakah permainan itu dalam keadaan akhir, dan jika ya, menentukan pemenangnya.

Saya akan merekomendasikan untuk melihat lebih dekat pada desain pertama dan ketiga Anda dan bekerja dengannya. Mungkin juga membantu untuk berpikir dalam hal prototipe. Seperti apa klien yang menggunakan antarmuka ini? Apakah satu pendekatan desain lebih masuk akal untuk mengimplementasikan klien yang sebenarnya akan membuat instantiate game dan memainkan game? Anda perlu menyadari apa yang berinteraksi dengannya. Dalam kasus khusus Anda, ini adalah Gamekelas, dan elemen terkait lainnya - Anda tidak dapat mendesain secara terpisah.


Karena Anda menyebut Anda seorang siswa, saya ingin membagikan beberapa hal dari waktu ketika saya menjadi TA untuk kursus desain perangkat lunak:

  • Pola hanyalah cara menangkap hal-hal yang telah bekerja di masa lalu, tetapi mengabstraksikan mereka ke titik di mana mereka dapat digunakan dalam desain lain. Setiap katalog pola desain memberi nama pada suatu pola, menjelaskan niatnya dan di mana ia dapat digunakan, dan situasi di mana ia pada akhirnya akan membatasi desain Anda.
  • Desain hadir dengan pengalaman. Cara terbaik untuk menjadi ahli dalam desain bukan hanya fokus pada aspek pemodelan, tetapi menyadari apa yang masuk ke dalam implementasi model itu. Desain yang paling elegan berguna jika tidak mudah diimplementasikan atau tidak cocok dengan desain sistem yang lebih besar atau dengan sistem lain.
  • Sangat sedikit desain yang "benar" atau "salah". Selama desain memenuhi persyaratan sistem, itu tidak mungkin salah. Begitu ada pemetaan dari setiap persyaratan menjadi beberapa representasi tentang bagaimana sistem akan memenuhi persyaratan itu, desain tidak bisa salah. Ini hanya kualitatif pada titik ini tentang konsep-konsep seperti fleksibilitas atau reusability atau testability atau rawatan.

Terima kasih atas saran yang bagus, terutama poin Anda tentang fakta bahwa itu berada pada level abstraksi yang salah. Saya telah mengubahnya sekarang menjadi GameTemplateyang terasa jauh lebih baik. Itu juga memungkinkan saya untuk menggabungkan metode pabrik untuk menginisialisasi pemain, papan, dll.
Mekswoll

3

Kebingungan Anda dibenarkan. Masalahnya adalah bahwa pola tidak saling eksklusif.

Metode template adalah dasar untuk banyak pola lain, seperti Strategi dan Negara. Pada dasarnya, antarmuka Strategi berisi satu atau lebih metode templat, masing-masing memerlukan semua objek yang menerapkan strategi untuk memiliki (setidaknya) sesuatu seperti metode doAction (). Ini memungkinkan strategi untuk saling menggantikan.

Di Jawa, sebuah antarmuka tidak lain adalah serangkaian metode templat. Demikian juga, setiap metode abstrak pada dasarnya adalah metode templat. Pola ini (antara lain) dikenal oleh para perancang bahasa, jadi mereka membangunnya.

@ThomasOwens menawarkan saran luar biasa untuk mendekati masalah khusus Anda.


0

Jika Anda terganggu oleh pola desain, saran saya kepada Anda adalah membuat prototipe permainan terlebih dahulu, maka pola itu hanya akan melompat keluar ke arah Anda. Saya tidak berpikir itu benar-benar mungkin atau disarankan untuk mencoba merancang sistem dengan sempurna terlebih dahulu dan kemudian mengimplementasikannya (dengan cara yang sama saya merasa bingung ketika orang mencoba untuk menulis seluruh program terlebih dahulu dan kemudian mengkompilasi, daripada melakukannya sedikit demi sedikit .) Masalahnya adalah bahwa tidak mungkin Anda akan memikirkan setiap skenario yang harus dihadapi logika Anda, dan selama fase implementasi Anda akan kehilangan semua harapan atau mencoba untuk tetap berpegang pada desain asli Anda yang cacat dan memperkenalkan peretasan, atau bahkan lebih buruk tidak memberikan apa-apa sama sekali.


2
Meskipun secara umum saya setuju dengan Anda , ini sebenarnya bukan jawaban yang memecahkan masalah OP. "Jangan lakukan itu" adalah jawaban, tetapi jawaban yang agak buruk jika tidak memberikan alternatif yang layak.
yannis

@YannisRizos Dan sementara saya setuju dengan Anda juga, saya masih berpikir dia memberikan saran yang bagus (atau wawasan jika saran bukan kata yang tepat). Karena alasan itu, +1. Meskipun demikian, ya itu bukan jawaban yang sangat membantu secara teknis .
dibeli777

-1

Mari kita turun ke paku payung kuningan. Sama sekali tidak perlu untuk antarmuka Game, tidak ada pola desain, tidak ada kelas abstrak, dan tidak ada UML.

Jika Anda memiliki jumlah kelas dukungan yang wajar, seperti UI, simulasi, dan apa pun, maka pada dasarnya semua kode khusus non-game-logika Anda tetap digunakan kembali. Selain itu, pengguna Anda tidak mengubah gimnya secara dinamis. Anda tidak membalik di 30Hz antara game. Anda memainkan satu game selama sekitar setengah jam. Jadi polimorfisme "dinamis" Anda sebenarnya tidak dinamis sama sekali. Agak statis.

Jadi cara yang masuk akal untuk pergi ke sini adalah dengan menggunakan abstraksi fungsional generik, seperti C # Actionatau C ++ std::function, membuat satu Mancala, satu Wari, dan satu kelas Kalah, dan pergi dari sana.

std::unordered_map<std::string, std::function<void()>> games = {
    { "Kalah", [] { return Kalah(); } },
    { "Mancala", [] { return Mancala(); } },
    { "Wari", [] { return Wari(); } }
};
void play() {
    std::function<void()> f;
    f = games[GetChoiceFromUI()];
    f();
    if (PlayAgain()) return play();
}
int main() {
    play();
}

Selesai

Anda tidak memanggil Game. Game memanggil Anda.


3
Saya tidak melihat bagaimana ini membantu sama sekali. Orang yang mengajukan pertanyaan ini adalah seorang siswa. Dia secara eksplisit bertanya tentang prinsip-prinsip desain dan interaksi antara dua pola desain. Mengatakan bahwa tidak ada kebutuhan untuk pola desain atau UML bisa benar dalam beberapa kasus di industri, tetapi berpikir tentang model desain, pola desain, dan UML bisa menjadi titik latihan yang ditanyakan.
Thomas Owens

3
Tidak ada yang bisa dikatakan tentang mereka, karena tidak ada tempat yang mereka terapkan. Tidak ada gunanya menghabiskan waktu Anda berpikir tentang bagaimana Anda akan benar-benar merancang desain menggunakan pola desain, kecuali jika Anda berniat untuk menjadi pelajaran tentang bagaimana tidak menggunakannya.
DeadMG

4
Ada tren yang mengkhawatirkan / mengganggu di SoftDev di mana pola desain yang digunakan dianggap lebih penting daripada hanya menyelesaikan masalah. Ada yang namanya over-engineering.
James

2
@DeadMG: sementara Anda berdua pada dasarnya benar, dalam kasus OP masalahnya lulus ujian, dan solusi untuk masalah itu adalah dengan menggunakan pola desain dan UML. Tidak peduli seberapa benar kita, jika profesornya tidak setuju dengan solusinya, dia tidak akan lulus.
Goran Jovic

2
Saya seluruh hidup saya selalu berpikir itu adalah "pajak kuningan" ... Wow, "kuningan paku payung" membuat jalan lebih masuk akal. lol
buy777
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.