Programiranje

Java Nasvet 68: Naučite se, kako v Java uvesti vzorec ukaza

Vzorci oblikovanja ne samo pospešijo fazo načrtovanja objektno usmerjenega projekta (OO), temveč tudi povečajo produktivnost razvojne skupine in kakovost programske opreme. A Ukazni vzorec je vedenjski vzorec predmeta, ki nam omogoča popolno ločitev med pošiljateljem in prejemnikom. (A pošiljatelj je objekt, ki prikliče operacijo, in sprejemnik je objekt, ki prejme zahtevo za izvedbo določene operacije. S ločevanje, pošiljatelj ne pozna Sprejemnik(vmesnik.) Izraz prošnja tukaj se nanaša na ukaz, ki ga je treba izvesti. Vzorec ukaza nam omogoča tudi spreminjanje, kdaj in kako je zahteva izpolnjena. Zato nam ukazni vzorec zagotavlja tako fleksibilnost kot tudi razširljivost.

V programskih jezikih, kot je C, kazalci funkcij se uporabljajo za odpravo velikanskih stavkov o preklopih. (Za podrobnejši opis glejte "Nasvet Java 30: Polimorfizem in Java".) Ker Java nima kazalcev funkcij, lahko uporabimo vzorec Command za izvajanje povratnih klicev. To boste videli v prvem spodnjem primeru kode, imenovanem TestCommand.java.

Razvijalci, ki so navajeni uporabljati kazalce funkcij v drugem jeziku, bi morda želeli uporabiti Metoda objekte API-ja Reflection na enak način. Na primer, v svojem članku "Java Reflection" Paul Tremblett vam pokaže, kako uporabljati Reflection za izvajanje transakcij brez uporabe stavkov preklopa. Temu skušnjavi sem se uprl, saj Sun odsvetuje uporabo Reflection API, kadar bodo zadostovala druga orodja, ki so bolj naravna programskemu jeziku Java. (Glejte Vire za povezave do Tremblettovega članka in za stran z vadbo Sun's Reflection.) Če ne boste uporabili programa, ga boste lažje odstranili in vzdrževali. Metoda predmetov. Namesto tega morate definirati vmesnik in ga implementirati v razrede, ki izvajajo potrebno dejanje.

Zato predlagam, da za izvajanje kazalcev funkcij uporabite vzorec Command v kombinaciji z dinamičnim mehanizmom za nalaganje in vezavo Java. (Za podrobnosti o dinamičnem mehanizmu nalaganja in vezave Java glejte James Gosling in Henry McGilton v "Jezikovnem okolju Java - bela knjiga", ki je navedena v virih.)

Z upoštevanjem zgornjega predloga izkoriščamo polimorfizem, ki ga zagotavlja uporaba vzorca Command, da odstranimo velikanske stavke preklopa, kar ima za posledico razširljive sisteme. Prav tako izkoriščamo edinstvene mehanizme dinamičnega nalaganja in vezave Java, da zgradimo dinamičen in dinamično razširljiv sistem. To je prikazano v drugem vzorčnem primeru spodnje kode, imenovanem TestTransactionCommand.java.

Vzorec ukaza pretvori samo zahtevo v objekt. Ta predmet je mogoče shraniti in prenašati tako kot druge predmete. Ključ tega vzorca je Ukaz vmesnik, ki razglasi vmesnik za izvajanje operacij. V svoji najpreprostejši obliki ta vmesnik vključuje povzetek izvršiti delovanje. Vsak beton Ukaz razred določa par sprejemnik-dejanje s shranjevanjem datoteke Sprejemnik kot spremenljivka primerka. Ponuja različne izvedbe izvrši () za sklic zahteve. The Sprejemnik ima znanje, potrebno za izvedbo zahteve.

Slika 1 spodaj prikazuje Preklopi - združevanje Ukaz predmetov. Ima flipUp () in flipDown () v svojem vmesniku. Preklopi se imenuje klicatelj ker prikliče operacijo izvrševanja v ukaznem vmesniku.

Konkreten ukaz, LightOnCommand, izvaja izvršiti delovanje ukaznega vmesnika. Ima znanje, da pokliče ustreznega Sprejemnik delovanje predmeta. V tem primeru deluje kot adapter. Po izrazu adapter, Mislim, da beton Ukaz je preprost konektor, ki povezuje Klicatelj in Sprejemnik z različnimi vmesniki.

Naročnik ustvari Klicatelj, Sprejemnikin konkretni ukazni predmeti.

Slika 2, diagram zaporedja, prikazuje interakcije med predmeti. To ponazarja, kako Ukaz ločuje Klicatelj Iz Sprejemnik (in zahteva, ki jo izvede). Naročnik ustvari konkreten ukaz s parametriranjem svojega konstruktorja z ustreznim Sprejemnik. Nato shrani Ukaz v Klicatelj. The Klicatelj pokliče konkreten ukaz, ki ima znanje za izvedbo želenega Dejanje () delovanje.

Naročnik (glavni program na seznamu) ustvari konkretno Ukaz predmet in nastavi svoj Sprejemnik. Kot Klicatelj predmet, Preklopi shranjuje beton Ukaz predmet. The Klicatelj izda zahtevo s klicem izvršiti na Ukaz predmet. Beton Ukaz objekt prikliče operacije na svojem Sprejemnik za izvedbo zahteve.

Ključna ideja tukaj je, da se konkretni ukaz registrira z Klicatelj in Klicatelj jo pokliče nazaj in izvrši ukaz na Sprejemnik.

Primer kode vzorca ukaza

Oglejmo si preprost primer, ki prikazuje mehanizem povratnega klica, dosežen z vzorcem Command.

Primer prikazuje a Ventilator in a Svetloba. Naš cilj je razviti a Preklopi ki lahko vklopi ali izklopi predmet. Vidimo, da Ventilator in Svetloba imajo različne vmesnike, kar pomeni Preklopi mora biti neodvisen od Sprejemnik ali ne pozna kode> Sprejemnikov vmesnik. Da bi rešili ta problem, moramo vsakega izmed parametrov parametrirati Preklopis z ustreznim ukazom. Očitno je Preklopi priključen na Svetloba bo imel drugačen ukaz kot Preklopi priključen na Ventilator. The Ukaz razred mora biti abstrakten ali vmesnik, da to deluje.

Ko je konstruktor za a Preklopi se prikliče, se parametrizira z ustreznim naborom ukazov. Ukazi bodo shranjeni kot zasebne spremenljivke Preklopi.

Ko flipUp () in flipDown () operacij, bodo preprosto naredili ustrezen ukaz za izvrši (). The Preklopi ne bo imel pojma, kaj se zgodi kot posledica izvrši () klic.

TestCommand.java razred Fan {public void startRotate () {System.out.println ("Ventilator se vrti"); } public void stopRotate () {System.out.println ("Ventilator se ne vrti"); }} class Light {public void turnOn () {System.out.println ("Light is on"); } public void turnOff () {System.out.println ("Lučka je izključena"); }} class Switch {private Command UpCommand, DownCommand; javno stikalo (ukaz gor, ukaz dol) {UpCommand = gor; // konkretni ukaz se registrira s prikličiteljem DownCommand = Down; } void flipUp () {// invoker pokliče nazaj konkretni ukaz, ki izvrši ukaz na sprejemniku UpCommand. izvršiti (); } void flipDown () {DownCommand. izvršiti (); }} razred LightOnCommand izvaja ukaz {private Light myLight; public LightOnCommand (Light L) {myLight = L; } javna void izvedba () {myLight. vklopiti( ); }} razred LightOffCommand izvaja ukaz {private Light myLight; public LightOffCommand (Light L) {myLight = L; } javna void izvedba () {myLight. ugasni( ); }} razred FanOnCommand izvaja ukaz {private Fan myFan; javni FanOnCommand (Fan F) {myFan = F; } javna void izvedba () {myFan. startRotate (); }} razred FanOffCommand izvaja ukaz {private Fan myFan; javni FanOffCommand (Fan F) {myFan = F; } public void execute () {myFan. stopRotate (); }} javni razred TestCommand {public static void main (String [] args) {Light testLight = new Light (); LightOnCommand testLOC = nov LightOnCommand (testLight); LightOffCommand testLFC = nov LightOffCommand (testLight); Switch testSwitch = novo stikalo (testLOC, testLFC); testSwitch.flipUp (); testSwitch.flipDown (); Test ventilatorja Fan = nov ventilator (); FanOnCommand foc = nov FanOnCommand (testFan); FanOffCommand ffc = nov FanOffCommand (testFan); Switch ts = novo stikalo (foc, ffc); ts.flipUp (); ts.flipDown (); }} Command.java javni vmesnik Ukaz {public abstract void execute (); } 

V zgornjem primeru kode opazite, da vzorec Command popolnoma loči objekt, ki prikliče operacijo - (Preklopi) - od tistih, ki imajo znanje za njegovo izvajanje - Svetloba in Ventilator. To nam daje veliko prilagodljivosti: objekt, ki izda zahtevo, mora vedeti le, kako jo izda; ni treba vedeti, kako bo zahteva izvedena.

Ukazni vzorec za izvajanje transakcij

Vzorec ukaza je znan tudi kot ukrepanje ali vzorec transakcij. Upoštevajmo strežnik, ki sprejema in obdeluje transakcije, ki jih dostavijo odjemalci prek povezave vtičnice TCP / IP. Te transakcije so sestavljene iz ukaza, ki mu sledi nič ali več argumentov.

Razvijalci lahko za vsak ukaz uporabljajo stavek preklopnika z velikimi črkami. Uporaba Preklopi izjave med kodiranjem so znak slabe zasnove v fazi načrtovanja objektno usmerjenega projekta. Ukazi predstavljajo objektno usmerjen način za podporo transakcijam in jih je mogoče uporabiti za reševanje te težave z načrtovanjem.

V odjemalski kodi programa TestTransactionCommand.java, so vse zahteve vključene v generično TransactionCommand predmet. The TransactionCommand konstruktor ustvari odjemalec in ga registrira v CommandManager. Zahteve v čakalni vrsti se lahko izvedejo ob različnih časih s klicem runCommands (), kar nam daje veliko prilagodljivosti. Omogoča nam tudi sestavljanje ukazov v sestavljeni ukaz. imam tudi CommandArgument, CommandReceiver, in CommandManager razredi in podrazredi TransactionCommand - in sicer AddCommand in Odštej ukaz. Sledi opis vsakega od teh razredov:

  • CommandArgument je pomožni razred, ki hrani argumente ukaza. Lahko ga napišete za poenostavitev naloge posredovanja velikega ali spremenljivega števila argumentov katere koli vrste.

  • CommandReceiver izvaja vse metode obdelave ukazov in se izvaja kot Singleton vzorec.

  • CommandManager je klicatelj in je Preklopi enakovredno prejšnjemu primeru. Shranjuje generično TransactionCommand predmet v svojem zasebnem myCommand spremenljivka. Kdaj runCommands () se prikliče, pokliče izvrši () ustreznega TransactionCommand predmet.

V Javi je mogoče poiskati definicijo razreda z nizom, ki vsebuje njegovo ime. V izvrši () delovanje TransactionCommand class, izračunam ime razreda in ga dinamično povežem v delujoči sistem - to pomeni, da se razredi naložijo sproti, kot je potrebno. Kot ime podrazreda ukazov za transakcije uporabljam konvencijo poimenovanja, ime ukaza, povezano z nizom "Ukaz", tako da ga je mogoče dinamično naložiti.

Upoštevajte, da Razred predmet, ki ga vrne newInstance () je treba oddati na ustrezen tip. To pomeni, da mora novi razred bodisi implementirati vmesnik bodisi razvrstiti obstoječi razred, ki je programu znan v času prevajanja. V tem primeru, odkar izvajamo Ukaz vmesnik, to ni problem.

$config[zx-auto] not found$config[zx-overlay] not found