Programmēšana

Ievads dizaina modeļos, 2. daļa: Pārskatīta četru bandu grupa

Šīs trīsdaļīgās sērijas 1. daļā, kurā tika ieviesti dizaina modeļi, es minēju Dizaina raksti: atkārtoti lietojama objektorientēta dizaina elementi. Šo klasiku uzrakstīja Ērihs Gamma, Ričards Helms, Ralfs Džonsons un Džons Vlisīds, kurus kopīgi dēvēja par Četru bandu. Kā zinās lielākā daļa lasītāju, Dizaina modeļi iepazīstina ar 23 programmatūras dizaina modeļiem, kas iekļaujas 1. daļā apskatītajās kategorijās: Radošais, strukturālais un uzvedības.

Dizaina modeļi vietnē JavaWorld

David Geary Java dizaina modeļu sērija ir meistarīgs ievads daudziem Java kodā esošo četru modeļu bandas.

Dizaina modeļi ir kanoniska lasīšana programmatūras izstrādātājiem, taču daudzus jaunus programmētājus izaicina tā atsauces formāts un darbības joma. Katrs no 23 modeļiem ir sīki aprakstīts veidnes formātā, kas sastāv no 13 sadaļām, un tas var būt daudz sagremojams. Vēl viens izaicinājums jaunajiem Java izstrādātājiem ir tas, ka četru modeļu grupa sastāv no objektorientētas programmēšanas, izmantojot piemērus, kuru pamatā ir C ++ un Smalltalk, nevis Java kods.

Šajā apmācībā es no Java izstrādātāja viedokļa izpakošu divus no visbiežāk izmantotajiem modeļiem - stratēģiju un apmeklētāju. Stratēģija ir diezgan vienkāršs modelis, kas kalpo par piemēru tam, kā kājas samitrināt, izmantojot GoF dizaina modeļus kopumā; Apmeklētājs ir sarežģītāks un vidēja mēroga. Sākšu ar piemēru, kuram vajadzētu demistificēt dubulto nosūtīšanas mehānismu, kas ir svarīga apmeklētāju modeļa sastāvdaļa. Tad es parādīšu Apmeklētāja modeli kompilatora lietošanas gadījumā.

Sekojot maniem piemēriem šeit, jums vajadzētu palīdzēt izpētīt un izmantot citus GoF modeļus. Piedāvāšu arī padomus, kā maksimāli izmantot grāmatu “Četru banda”, un nobeigšu ar kritikas kopsavilkumu par dizaina modeļu izmantošanu programmatūras izstrādē. Šī diskusija varētu būt īpaši aktuāla izstrādātājiem, kuri vēl nav izstrādājuši programmu.

Izpakošanas stratēģija

The Stratēģija modelis ļauj definēt algoritmu saimi, piemēram, tos, kurus izmanto šķirošanai, teksta sastādīšanai vai izkārtojuma pārvaldībai. Stratēģija ļauj arī iekapsulēt katru algoritmu savā klasē un padarīt tos savstarpēji aizvietojamus. Katrs iekapsulētais algoritms ir pazīstams kā a stratēģiju. Izpildes laikā klients izvēlas savām vajadzībām atbilstošu algoritmu.

Kas ir klients?

A klients ir jebkura programmatūras daļa, kas mijiedarbojas ar dizaina modeli. Lai gan klients parasti ir objekts, klients varētu būt arī kods lietojumprogrammā public static void main (String [] argumenti) metodi.

Atšķirībā no dekoratora modeļa, kas koncentrējas uz objekta modeļa maiņu ādavai izskats, Stratēģija koncentrējas uz objekta mainīšanu iekšas, kas nozīmē tā mainīgo uzvedību. Stratēģija ļauj izvairīties no vairāku nosacītu paziņojumu izmantošanas, pārvietojot nosacītās filiāles uz savām stratēģijas klasēm. Šīs klases bieži rodas no abstraktas superklases, uz kuru klients atsaucas un izmanto, lai mijiedarbotos ar konkrētu stratēģiju.

No abstraktā viedokļa stratēģija ietver Stratēģija, BetonsStrategyx, un Konteksts veidi.

Stratēģija

Stratēģija nodrošina kopēju saskarni visiem atbalstītajiem algoritmiem. 1. saraksts parāda Stratēģija interfeiss.

Uzskaitīšana 1. void execute (int x) jāīsteno visās konkrētajās stratēģijās

publiskās saskarnes stratēģija {public void execute (int x); }

Ja konkrētas stratēģijas netiek parametrizētas ar kopīgiem datiem, varat tās ieviest, izmantojot Java interfeiss iezīme. Vietās, kur tās ir parametri, jūs deklarētu abstraktu klasi. Piemēram, teksta izlīdzināšanas pa labi, centra izlīdzināšanas un pamatojuma stratēģijās ir kopīgs a jēdziens platums kurā veikt teksta izlīdzināšanu. Tātad jūs to paziņotu platums abstraktā klasē.

BetonsStrategyx

Katrs BetonsStrategyx ievieš kopējo saskarni un nodrošina algoritma ieviešanu. 2. saraksts īsteno 1. sarakstu Stratēģija saskarni, lai aprakstītu konkrētu konkrētu stratēģiju.

Saraksts 2. ConcreteStrategyA izpilda vienu algoritmu

publiskā klase ConcreteStrategyA īsteno stratēģiju {@Override public void execute (int x) {System.out.println ("izpildes stratēģija A: x =" + x); }}

The void execute (int x) 2. saraksta metode identificē konkrētu stratēģiju. Iedomājieties šo metodi kā abstrakciju kaut kam noderīgākam, piemēram, noteikta veida šķirošanas algoritmam (piemēram, Bubble Sort, Insertion Sort vai Quick Sort) vai noteikta veida izkārtojuma pārvaldniekam (piemēram, Flow Layout, Border Layout vai Režģa izkārtojums).

Sarakstā 3 parādīta sekunde Stratēģija ieviešana.

Saraksts 3. ConcreteStrategyB izpilda citu algoritmu

publiskā klase ConcreteStrategyB īsteno stratēģiju {@Override public void execute (int x) {System.out.println ("izpildes stratēģija B: x =" + x); }}

Konteksts

Konteksts sniedz kontekstu, kurā tiek izmantota konkrētā stratēģija. 2. un 3. sarakstā ir dati, kas tiek nodoti no konteksta stratēģijai, izmantojot metodes parametru. Tā kā vispārīga stratēģijas saskarne ir kopīga visām konkrētajām stratēģijām, dažām no tām var nebūt vajadzīgi visi parametri. Lai izvairītos no izšķērdētiem parametriem (it īpaši, nododot daudz dažādu argumentu tikai dažām konkrētām stratēģijām), tā vietā jūs varētu nodot atsauci uz kontekstu.

Tā vietā, lai nodotu konteksta atsauci uz metodi, jūs to varētu saglabāt abstraktā klasē, padarot jūsu metodes izsaukumus bez parametriem. Tomēr kontekstā būtu jānorāda plašāka saskarne, kas ietvertu līgumu par piekļuvi konteksta datiem vienotā veidā. Rezultāts, kā parādīts 4. sarakstā, ir ciešāka saikne starp stratēģijām un to kontekstu.

Saraksts 4. Konteksts ir konfigurēts ar ConcreteStrategyx instanci

klases konteksts {privātā stratēģijas stratēģija; publiskais konteksts (stratēģijas stratēģija) {setStrategy (stratēģija); } public void executeStrategy (int x) {strategy.execute (x); } public void setStrategy (stratēģijas stratēģija) {this.strategy = stratēģija; }}

The Konteksts 4. saraksta klase glabā stratēģiju, kad tā tiek izveidota, nodrošina metodi, lai pēc tam mainītu stratēģiju, un nodrošina citu metodi pašreizējās stratēģijas izpildei. Izņemot stratēģijas nodošanu konstruktoram, šo modeli var redzēt java.awt .Container klasē, kura void setLayout (LayoutManager pārvaldnieks) un void doLayout () metodes nosaka un izpilda izkārtojuma pārvaldnieka stratēģiju.

StrategyDemo

Mums ir nepieciešams klients, lai parādītu iepriekšējos veidus. 5. sarakstā ir a StrategyDemo klientu klase.

Saraksts 5. StrategyDemo

publiskā klase StrategyDemo {public static void main (String [] args) {Context context = new Context (new ConcreteStrategyA ()); context.executeStrategy (1); context.setStrategy (jauna ConcreteStrategyB ()); context.executeStrategy (2); }}

Konkrēta stratēģija ir saistīta ar a Konteksts piemēram, kad tiek izveidots konteksts. Pēc tam stratēģiju var mainīt, izmantojot konteksta metodes izsaukumu.

Ja jūs apkopojat šīs klases un palaižat StrategyDemo, jums jāievēro šāda izeja:

izpildes stratēģija A: x = 1 izpildes stratēģija B: x = 2

Apmeklētāja modeļa pārskatīšana

Apmeklētājs ir pēdējais programmatūras dizaina modelis, kurā parādīsies Dizaina modeļi. Lai gan šis uzvedības modelis grāmatā ir parādīts pēdējais alfabētisku apsvērumu dēļ, daži uzskata, ka tam vajadzētu būt pēdējam sarežģītības dēļ. Apmeklētāja jaunpienācēji bieži cīnās ar šo programmatūras dizaina modeli.

Kā paskaidrots Dizaina modeļi, apmeklētājs ļauj jums pievienot operācijas klasēm, nemainot tās, mazliet burvju, ko veicina tā sauktā dubultās nosūtīšanas tehnika. Lai saprastu apmeklētāju modeli, mums vispirms ir jāsagremo dubultā nosūtīšana.

Kas ir dubultā nosūtīšana?

Java un daudzas citas valodas atbalsta polimorfisms (daudzas formas), izmantojot tehniku, kas pazīstama kā dinamiska nosūtīšana, kurā izpildlaikā ziņojums tiek piesaistīts noteiktai koda secībai. Dinamiskā nosūtīšana tiek klasificēta kā vienreizēja vai vairākkārtēja nosūtīšana:

  • Viena nosūtīšana: Ņemot vērā klases hierarhiju, kurā katra klase īsteno vienu un to pašu metodi (tas ir, katra apakšklase ignorē iepriekšējās klases versijas metodi), un, ņemot vērā mainīgo, kuram piešķirts vienas no šīm klasēm gadījums, tipu var noskaidrot tikai vietnē izpildlaiks. Piemēram, pieņemsim, ka katra klase ievieš metodi izdrukāt (). Pieņemsim arī, ka viena no šīm klasēm tiek izpildīta izpildes laikā un tās mainīgais tiek piešķirts mainīgajam a. Kad Java kompilators sastopas a.druka ();, tā var to tikai pārbaudīt atipā ir a izdrukāt () metodi. Tā nezina, kuru metodi zvanīt. Izpildes laikā virtuālā mašīna pārbauda atsauci mainīgajā a un izdomā faktisko tipu, lai izsauktu pareizo metodi. Šī situācija, kurā ieviešanas pamatā ir viens tips (instances tips), ir pazīstama kā viena nosūtīšana.
  • Vairākas nosūtīšanas: Atšķirībā no vienas nosūtīšanas, kur viens arguments nosaka, kuru šī nosaukuma metodi izmantot, vairākkārtēja nosūtīšana izmanto visus savus argumentus. Citiem vārdiem sakot, tas vispārina dinamisko nosūtīšanu darbam ar diviem vai vairākiem objektiem. (Ņemiet vērā, ka argumentu vienā sūtījumā parasti norāda ar perioda atdalītāju pa kreisi no izsauktā metodes nosaukuma, piemēram, a iekšā a.print ().)

Visbeidzot, dubultā nosūtīšana ir īpašs vairākkārtējas nosūtīšanas gadījums, kad izsaukumā ir iesaistīti divu objektu izpildlaika veidi. Lai gan Java atbalsta vienreizēju nosūtīšanu, tā neatbalsta divkāršu nosūtīšanu tieši. Bet mēs varam to simulēt.

Vai mēs pārāk paļaujamies uz divkāršu nosūtīšanu?

Emuāru autors Dereks Greers uzskata, ka dubultās nosūtīšanas izmantošana var norādīt uz dizaina problēmu, kas varētu ietekmēt lietojumprogrammas uzturēšanu. Lai iegūtu sīkāku informāciju, izlasiet Greera emuāra ziņojumu "Divkāršā nosūtīšana ir koda smarža" un ar to saistītos komentārus.

Divkāršās nosūtīšanas simulēšana Java kodā

Vikipēdijas ieraksts par divkāršu nosūtīšanu sniedz uz C ++ balstītu piemēru, kas parāda, ka tas ir vairāk nekā funkciju pārslodze. 6. sarakstā es uzrādīju Java ekvivalentu.

Saraksts 6. Dubultā nosūtīšana Java kodā

publiskā klase DDDemo {public static void main (String [] args) {asteroīds theAsteroid = jauns asteroīds (); SpaceShip theSpaceShip = jauns SpaceShip (); ApolloSpacecraft theApolloSpacecraft = jauns ApolloSpacecraft (); theAsteroid.collideWith (theSpaceShip); theAsteroid.collideWith (theApolloSpacecraft); System.out.println (); ExplodingAsteroid theExplodingAsteroid = jauns ExplodingAsteroid (); theExplodingAsteroid.collideWith (theSpaceShip); theExplodingAsteroid.collideWith (TheApolloSpacecraft); System.out.println (); Asteroīds theAsteroidReference = sprādziena asteroīds; theAsteroidReference.collideWith (theSpaceShip); theAsteroidReference.collideWith (theApolloSpacecraft); System.out.println (); SpaceShip theSpaceShipReference = theApolloSpacecraft; theAsteroid.collideWith (theSpaceShipReference); theAsteroidReference.collideWith (theSpaceShipReference); System.out.println (); theSpaceShipReference = theApolloSpacecraft; theAsteroidReference = TheExplodingAsteroid; theSpaceShipReference.collideWith (asteroīds); theSpaceShipReference.collideWith (theAsteroidReference); }} klases kosmosa kuģis {void collideWith (asteroīds inAsteroid) {inAsteroid.collideWith (šis); }} klases ApolloSpacecraft paplašina SpaceShip {void collideWith (asteroīds inAsteroid) {inAsteroid.collideWith (šis); }} klases asteroīds {void collideWith (SpaceShip s) {System.out.println ("Asteroīds trāpīja kosmosa kuģī"); } void collideWith (ApolloSpacecraft as) {System.out.println ("Asteroīds trāpīja ApolloSpacecraft"); }} klase ExplodingAsteroid izstiepj asteroīdu {void collideWith (SpaceShip s) {System.out.println ("ExplodingAsteroid hit a SpaceShip"); } void collideWith (ApolloSpacecraft as) {System.out.println ("ExplodingAsteroid trāpīja ApolloSpacecraft"); }}

6. saraksts pēc iespējas precīzāk seko tā C ++ līdziniekam. Pēdējās četras rindas galvenais () metodi kopā ar void collideWith (asteroīds asteroīdā) metodes Kosmosa kuģis un ApolloSpacecraft demonstrēt un simulēt dubultu nosūtīšanu.

Apsveriet šādu fragmentu no galvenais ():

theSpaceShipReference = theApolloSpacecraft; theAsteroidReference = TheExplodingAsteroid; theSpaceShipReference.collideWith (asteroīds); theSpaceShipReference.collideWith (theAsteroidReference);

Trešajā un ceturtajā rindā tiek izmantota viena nosūtīšana, lai noskaidrotu pareizo sadursme ar () metode ( Kosmosa kuģis vai ApolloSpacecraft), lai izsauktu. Šo lēmumu pieņem virtuālā mašīna, pamatojoties uz mapē saglabāto atsauču tipu theSpaceShipReference.

No iekšienes sadursme ar (), inAsteroid.collideWith (šis); izmanto vienu nosūtīšanu, lai noskaidrotu pareizo klasi (Asteroīds vai Sprāgstošs asteroīds), kas satur vēlamo sadursme ar () metodi. Tā kā Asteroīds un Sprāgstošs asteroīds pārslodze sadursme ar (), argumenta veids šo (Kosmosa kuģis vai ApolloSpacecraft) tiek izmantots, lai atšķirtu pareizo sadursme ar () metode zvanīšanai.

Un līdz ar to mēs esam paveikuši dubultu nosūtīšanu. Atgādinot, mēs vispirms piezvanījām sadursme ar () iekšā Kosmosa kuģis vai ApolloSpacecraft, un pēc tam izmantoja savu argumentu un šo piezvanīt vienam no sadursme ar () metodes Asteroīds vai Sprāgstošs asteroīds.

Kad tu skrien DDDemo, jums jāievēro šāda izeja:

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