Dizaino modeliai ne tik pagreitina į objektą orientuoto (OO) projekto projektavimo etapą, bet ir padidina kūrėjų komandos produktyvumą ir programinės įrangos kokybę. A Komandos modelis yra objekto elgesio modelis, leidžiantis mums visiškai atsieti siuntėją ir imtuvą. (A siuntėjas yra objektas, kuris iškviečia operaciją, ir a imtuvas yra objektas, gaunantis prašymą atlikti tam tikrą operaciją. Su atsiejimas, siuntėjas neturi žinių apie Imtuvas
sąsaja.) Terminas prašymą čia nurodo komandą, kurią reikia vykdyti. „Command“ modelis taip pat leidžia mums keisti, kada ir kaip įvykdoma užklausa. Todėl komandų modelis suteikia mums lankstumo ir išplėtimo galimybių.
Programavimo kalbomis, tokiomis kaip C, funkcijų rodyklės yra naudojami milžiniškų jungiklių teiginiams pašalinti. (Išsamesnį aprašymą žr. „Java 30 patarimas: polimorfizmas ir„ Java “.) Kadangi„ Java “neturi funkcijų rodyklių, mes galime naudoti komandų šabloną atgaliniams skambučiams įgyvendinti. Tai pamatysite pirmame žemiau pateiktame kodo pavyzdyje, vadinamame TestCommand.java
.
Kūrėjai, įpratę naudoti funkcijų rodykles kita kalba, gali susigundyti naudoti Metodas
„Reflection“ API objektai tokiu pačiu būdu. Pavyzdžiui, savo straipsnyje „Java Reflection“ Paulas Tremblettas parodo, kaip naudoti „Reflection“ operacijoms įgyvendinti nenaudojant jungiklių sakinių. Aš atsispiriau šiai pagundai, nes „Sun“ nepataria naudoti „Reflection“ API, kai pakaks kitų natūralesnių „Java“ programavimo kalbos įrankių. (Žr. Šaltinius, kuriuose pateikiamos nuorodos į „Tremblett“ straipsnį ir „Sun“ atspindžio pamokų puslapį.) Jei nenaudosite, jūsų programą bus lengviau derinti ir prižiūrėti. Metodas
objektai. Vietoj to turėtumėte apibrėžti sąsają ir ją įdiegti klasėse, kurios atlieka reikiamą veiksmą.
Todėl funkcijų rodyklėms įgyvendinti siūlau naudoti komandų šabloną kartu su dinaminiu „Java“ įkėlimo ir įrišimo mechanizmu. (Išsamesnės informacijos apie dinaminį „Java“ įkėlimo ir įrišimo mechanizmą žr. Jameso Goslingo ir Henry McGiltono „Java kalbos aplinka - baltoji knyga“, pateiktą šaltiniuose.)
Laikydamiesi pirmiau pateikto pasiūlymo, mes išnaudojame polimorfizmą, kurį suteikia „Command“ šablonas, kad pašalintume milžiniškus jungiklių teiginius, dėl kurių atsiranda išplėstinės sistemos. Mes taip pat išnaudojame unikalius „Java“ dinaminius įkėlimo ir susiejimo mechanizmus, kad sukurtume dinamišką ir dinamiškai išplečiamą sistemą. Tai iliustruoja antrasis žemiau pateiktas kodo pavyzdys, vadinamas TestTransactionCommand.java
.
Komandos modelis paverčia patį prašymą objektu. Šį objektą galima laikyti ir perduoti aplinkui kaip kitus objektus. Šio modelio raktas yra a Komanda
sąsaja, kuri deklaruoja sąsają operacijoms vykdyti. Paprasčiausia forma šioje sąsajoje yra abstraktus vykdyti
operacija. Kiekvienas betonas Komanda
klasėje nurodoma imtuvo ir veiksmo pora, saugant Imtuvas
kaip egzemplioriaus kintamasis. Tai suteikia skirtingą programos įgyvendinimą vykdyti ()
būdas iškviesti užklausą. Imtuvas
turi žinių, reikalingų prašymui įvykdyti.
Žemiau pateiktame 1 paveiksle pavaizduota Perjungti
- visuma Komanda
objektai. Tai turi apversti aukštyn()
ir „flipDown“ ()
operacijas savo sąsajoje. Perjungti
yra vadinamas kviestinis nes komandų sąsajoje iškviečia vykdymo operaciją.
Konkreti komanda, „LightOnCommand“
, įgyvendina vykdyti
komandos sąsajos veikimas. Ji turi žinių paskambinti tinkamam Imtuvas
objekto veikimas. Šiuo atveju jis veikia kaip adapteris. Pagal terminą adapteris, Turiu omeny, kad betonas Komanda
objektas yra paprasta jungtis, jungianti Kvietėjas
ir Imtuvas
su skirtingomis sąsajomis.
Klientas akimirksniu Kvietėjas
, Imtuvas
ir konkretūs komandos objektai.
2 paveiksle, sekos schemoje, parodoma objektų sąveika. Tai iliustruoja kaip Komanda
atsieti Kvietėjas
nuo Imtuvas
(ir jo įvykdytą prašymą). Klientas sukuria konkrečią komandą, parametruodamas savo konstruktorių tinkamu Imtuvas
. Tada jis saugo Komanda
viduje konors Kvietėjas
. Kvietėjas
atšaukia konkrečią komandą, kuri turi žinių norimam įvykdyti Veiksmas ()
operacija.
Klientas (pagrindinė programa sąraše) sukuria konkretų Komanda
objektas ir nustato jo Imtuvas
. Kaip Kvietėjas
objektas, Perjungti
sandėliuoja betoną Komanda
objektas. Kvietėjas
išduoda prašymą skambindamas vykdyti
ant Komanda
objektas. Betonas Komanda
objektas iškviečia jo operacijas Imtuvas
įvykdyti prašymą.
Pagrindinė mintis yra ta, kad konkreti komanda užsiregistruoja Kvietėjas
ir Kvietėjas
skambina atgal, vykdydamas komandą Imtuvas
.
Komandos šablono pavyzdinis kodas
Pažvelkime į paprastą pavyzdį, iliustruojantį atgalinio ryšio mechanizmą, pasiektą naudojant „Command“ modelį.
Pavyzdys rodo a Ventiliatorius
ir a Šviesa
. Mūsų tikslas yra sukurti a Perjungti
kuris gali įjungti arba išjungti objektą. Mes matome, kad Ventiliatorius
ir Šviesa
turi skirtingas sąsajas, o tai reiškia Perjungti
turi būti nepriklausoma nuo Imtuvas
sąsaja arba ji neturi žinių apie kodą> Imtuvo sąsaja. Norėdami išspręsti šią problemą, turime nustatyti kiekvieną iš parametrų Perjungti
s su atitinkama komanda. Akivaizdu, kad Perjungti
prijungtas prie Šviesa
turės kitą komandą nei Perjungti
prijungtas prie Ventiliatorius
. Komanda
klasė turi būti abstrakti arba sąsaja, kad tai veiktų.
Kai konstruktorius a Perjungti
yra iškviečiamas, jis yra parametruojamas atitinkamu komandų rinkiniu. Komandos bus saugomos kaip privatūs Perjungti
.
Kai apversti aukštyn()
ir „flipDown“ ()
iškviečiamos operacijos, jos tiesiog atliks atitinkamą komandą vykdyti ()
. Perjungti
neįsivaizduos, kas nutiks dėl to vykdyti ()
skambinama.
TestCommand.java klasė „Fan“ {public void startRotate () {System.out.println ("Ventiliatorius sukasi"); } public void stopRotate () {System.out.println ("Ventiliatorius nesisuka"); }} klasės šviesa {public void turnOn () {System.out.println ("Šviesa įjungta"); } public void turnOff () {System.out.println ("Šviesa išjungta"); }} klasės jungiklis {privati komanda „UpCommand“, „DownCommand“; viešasis jungiklis (komanda aukštyn, žemyn) {upCommand = aukštyn; // konkreti komanda registruojasi pašaukikliu DownCommand = Down; } void flipUp () {// iškvietėjas iškviečia konkrečią komandą, kuri vykdo komandą imtuve „UpCommand“. vykdyti (); } void flipDown () {DownCommand. vykdyti (); }} klasės „LightOnCommand“ įgyvendina komandą {privatus „Light myLight“; viešoji „LightOnCommand“ (šviesa L) {myLight = L; } public void vykdyti () {myLight. įjungti( ); }} klasės „LightOffCommand“ įgyvendina komandą {privatus „Light myLight“; viešoji „LightOffCommand“ (šviesa L) {myLight = L; } public void vykdyti () {myLight. Išjunk( ); }} klasės „FanOnCommand“ įgyvendina komandą {privatus gerbėjas „myFan“; public FanOnCommand (Fan F) {myFan = F; } public void vykdyti () {myFan. startRotate (); }} klasės „FanOffCommand“ įgyvendina komandą {privatus gerbėjas „myFan“; viešas „FanOffCommand“ (F ventiliatorius) {myFan = F; } public void vykdyti () {myFan. stopRotate (); }} public class TestCommand {public static void main (String [] args) {Šviesos testLight = nauja Šviesa (); „LightOnCommand testLOC“ = nauja „LightOnCommand“ (testLight); „LightOffCommand testLFC“ = nauja „LightOffCommand“ (testLight); Jungiklis testSwitch = naujas jungiklis (testLOC, testLFC); testSwitch.flipUp (); testSwitch.flipDown (); Ventiliatoriaus testas Ventiliatorius = naujas ventiliatorius (); „FanOnCommand foc“ = naujas „FanOnCommand“ (testFan); FanOffCommand ffc = naujas FanOffCommand (testFan); Jungiklis ts = naujas jungiklis (foc, ffc); ts.flipUp (); ts.flipDown (); }} Command.java viešoji sąsaja Command {public abstract void execute (); }
Pirmiau pateiktame kodo pavyzdyje atkreipkite dėmesį, kad komandos modelis visiškai atsieja objektą, kuris iškviečia operaciją - (Perjungti)
- iš tų, kurie turi žinių tai atlikti - Šviesa
ir Ventiliatorius
. Tai suteikia mums daug lankstumo: prašymą pateikiantis objektas turi žinoti tik kaip jį išduoti; jai nereikia žinoti, kaip bus vykdoma užklausa.
Komandų šablonas operacijoms įgyvendinti
Komandos modelis taip pat žinomas kaip veiksmas arba sandorio modelis. Panagrinėkime serverį, kuris priima ir apdoroja operacijas, kurias klientai teikia per TCP / IP lizdo jungtį. Šias operacijas sudaro komanda, po kurios pateikiama nulis ar daugiau argumentų.
Kūrėjai kiekvienai komandai gali naudoti jungiklio sakinį su didžiosiomis ir mažosiomis raidėmis. Naudojimas Perjungti
sakiniai kodavimo metu yra blogo dizaino ženklas projektavimo objektui skirto projekto etape. Komandos yra objektyvus būdas palaikyti operacijas ir gali būti naudojamos šiai dizaino problemai išspręsti.
Programos kliento kode TestTransactionCommand.java
, visos užklausos yra sujungtos į bendrąją „TransactionCommand“
objektas. „TransactionCommand“
konstruktorių sukuria klientas ir jis yra užregistruotas „CommandManager“
. Eilėje esančias užklausas galima įvykdyti skirtingu laiku paskambinus „runCommands“ ()
, kuris suteikia mums daug lankstumo. Tai taip pat suteikia mums galimybę surinkti komandas į sudėtinę komandą. aš taip pat turiu „CommandArgument“
, „CommandReceiver“
ir „CommandManager“
klasės ir poklasiai „TransactionCommand“
- būtent „AddCommand“
ir SubtractCommand
. Toliau pateikiamas kiekvienos iš šių klasių aprašymas:
„CommandArgument“
yra pagalbininkų klasė, kurioje saugomi komandos argumentai. Ją galima perrašyti, kad būtų supaprastinta užduotis perduoti didelį ar kintantį bet kokio tipo argumentų skaičių.„CommandReceiver“
įgyvendina visus komandų apdorojimo metodus ir yra įgyvendinamas kaip „Singleton“ modelis.„CommandManager“
yra kviestinis ir yraPerjungti
atitikmuo iš ankstesnio pavyzdžio. Jame saugomi generiniai vaistai„TransactionCommand“
objektas savo privačiame„myCommand“
kintamasis. Kada„runCommands“ ()
yra iškviečiamas, jis vadinavykdyti ()
tinkamų„TransactionCommand“
objektas.
„Java“ programoje galima ieškoti klasės apibrėžimo, suteikiant eilutę su jos pavadinimu. Viduje konors vykdyti ()
operacija „TransactionCommand“
klasę, aš apskaičiuoju klasės pavadinimą ir dinamiškai susieju jį su veikiančia sistema - tai yra, klasės, kaip reikalaujama, yra pakraunamos skraidant. Kaip operacijos komandos poklasio pavadinimą naudoju pavadinimų suteikimo tvarką, komandos pavadinimą, sujungtą eilute „Komanda“, kad ją būtų galima dinamiškai įkelti.
Atkreipkite dėmesį, kad Klasė
objektas, kurį grąžino newInstance ()
turi būti išmesta į atitinkamą tipą. Tai reiškia, kad naujoji klasė turi arba įdiegti sąsają, arba poklasį esamą klasę, kuri programai žinoma kompiliavimo metu. Šiuo atveju, kadangi mes įgyvendiname Komanda
sąsaja, tai nėra problema.