Saya memiliki implementasi pola Command yang lama ini. Ini semacam mengeluarkan Konteks melalui semua implementasi DIOperasi , tetapi saya sadari kemudian, dalam proses belajar dan belajar (yang tidak pernah berhenti), itu tidak optimal. Saya juga berpikir bahwa "mengunjungi" di sini tidak benar-benar cocok dan hanya membingungkan.
Saya sebenarnya berpikir untuk mengembalikan kode saya, juga karena Perintah seharusnya tidak tahu apa-apa tentang yang lain dan saat ini mereka semua berbagi pasangan nilai kunci yang sama. Sangat sulit untuk mempertahankan kelas mana yang memiliki nilai kunci apa, kadang-kadang mengarah ke variabel duplikat.
Contoh use case: katakanlah CommandB membutuhkan UserName yang ditetapkan oleh CommandA . Haruskah CommandA mengatur kunci UserNameForCommandB = John ? Atau haruskah mereka berbagi UserName = John -nilai kunci yang umum? Bagaimana jika UserName digunakan oleh Perintah ketiga?
Bagaimana saya bisa meningkatkan desain ini? Terima kasih!
class DIParameters {
public:
/**
* Parameter setter.
*/
virtual void setParameter(std::string key, std::string value) = 0;
/**
* Parameter getter.
*/
virtual std::string getParameter(std::string key) const = 0;
virtual ~DIParameters() = 0;
};
class DIOperation {
public:
/**
* Visit before performing execution.
*/
virtual void visitBefore(DIParameters& visitee) = 0;
/**
* Perform.
*/
virtual int perform() = 0;
/**
* Visit after performing execution.
*/
virtual void visitAfter(DIParameters& visitee) = 0;
virtual ~DIOperation() = 0;
};
sumber
Jawaban:
Saya agak khawatir tentang berubahnya parameter perintah Anda. Apakah benar-benar perlu membuat perintah dengan parameter yang terus berubah?
Masalah dengan pendekatan Anda:
Apakah Anda ingin utas / perintah lain mengubah parameter Anda saat
perform
sedang berlangsung?Apakah Anda ingin
visitBefore
dan objek yangvisitAfter
samaCommand
dipanggil denganDIParameter
objek yang berbeda ?Apakah Anda ingin seseorang memberi makan parameter ke perintah Anda, yang tidak diketahui perintahnya?
Semua ini dilarang oleh desain Anda saat ini. Sementara konsep parameter kunci-nilai umum memiliki kelebihan di kali, saya tidak suka sehubungan dengan kelas perintah generik.
Contoh konsekuensi:
Pertimbangkan realisasi konkret
Command
kelas Anda - sesuatu sepertiCreateUserCommand
. Sekarang jelas, ketika Anda meminta pengguna baru untuk dibuat, perintah akan membutuhkan nama untuk pengguna itu. Mengingat saya tahu kelasCreateUserCommand
-DIParameters
kelasnya, parameter mana yang harus saya atur?Saya dapat mengatur
userName
parameter, atauusername
.. apakah Anda memperlakukan parameter case dengan tidak sensitif? Saya tidak akan tahu benar .. oh, tunggu .. mungkin hanya sajaname
?Seperti yang Anda lihat kebebasan yang Anda peroleh dari pemetaan nilai kunci generik menyiratkan bahwa menggunakan kelas Anda sebagai seseorang yang tidak menerapkannya tidak sulit tanpa alasan. Anda setidaknya perlu memberikan beberapa konstanta untuk perintah Anda agar orang lain tahu kunci mana yang didukung oleh perintah itu.
Kemungkinan pendekatan desain yang berbeda:
Parameter
instance Anda yang tidak dapat diubah, Anda dapat dengan bebas menggunakannya kembali di antara berbagai perintah.UserParameter
kelas yang berisi persis parameter yang saya perlukan untuk perintah yang melibatkan pengguna, akan jauh lebih mudah untuk bekerja dengan API ini. Anda masih dapat memiliki pewarisan pada parameter, tetapi tidak masuk akal lagi bagi kelas perintah untuk mengambil parameter sewenang-wenang - di sisi pro tentu saja ini berarti bahwa pengguna API mengetahui parameter mana yang diperlukan secara tepat.visitBefore
danvisitAfter
, sementara juga menggunakannya kembali dengan parameter yang berbeda, Anda akan terbuka untuk masalah dipanggil dengan parameter yang berbeda. Jika parameternya harus sama pada beberapa pemanggilan metode, Anda perlu merangkumnya ke dalam perintah sedemikian rupa sehingga tidak dapat dialihkan untuk parameter lain di sela-sela panggilan.sumber
Apa yang baik tentang prinsip-prinsip desain adalah bahwa cepat atau lambat, mereka bertentangan satu sama lain.
Dalam situasi yang dijelaskan, saya pikir saya lebih suka pergi dengan semacam konteks di mana setiap perintah dapat mengambil informasi dari dan memasukkan informasi ke (terutama jika mereka adalah pasangan kunci-nilai). Ini didasarkan pada trade off: Saya tidak ingin perintah terpisah digabungkan hanya karena mereka adalah semacam input satu sama lain. Di dalam CommandB, saya tidak peduli bagaimana UserName diset - hanya karena itu ada untuk saya gunakan. Hal yang sama di CommandA: Saya mengatur informasinya, saya tidak ingin tahu apa yang dilakukan orang lain dengannya - juga siapa mereka.
Ini berarti semacam konteks lewat, yang menurut Anda buruk. Bagi saya, alternatifnya lebih buruk, terutama jika konteks kunci-nilai sederhana ini (bisa menjadi kacang sederhana dengan getter dan setter, untuk membatasi sedikit faktor "bentuk bebas") dapat memungkinkan solusi menjadi sederhana dan dapat diuji, dengan baik perintah terpisah, masing-masing dengan logika bisnisnya sendiri.
sumber
Mari kita asumsikan Anda memiliki antarmuka perintah:
Dan subjek:
Yang Anda butuhkan adalah:
Tetapkan
NameObserver& o
sebagai referensi ke CommandB. Sekarang setiap kali CommandA mengubah nama Subjek, CommandB dapat mengeksekusi dengan informasi yang benar. Jika nama digunakan oleh lebih banyak perintah, gunakan astd::list<NameObserver>
sumber
Saya tidak tahu apakah ini cara yang tepat untuk menangani ini pada Programer (dalam hal ini saya minta maaf), tetapi, setelah memeriksa semua jawaban di sini (@ Frank khususnya). Saya refactored kode saya dengan cara ini:
Terima kasih atas bantuannya dan saya harap saya tidak membuat kesalahan di sini :)
sumber