2011. január 29., szombat
2011. január 27., csütörtök
Építő (Builder)
Egy RTF (Rich Text Format) dokumentumcsere formátum olvasónak képesnek kell lennie az RTF számos egyéb szövegformátumba való konvertálásra. Az olvasó átalakíthatja sima ASCII szöveggé vagy egy interaktívan szerkeszthető szövegeszközzé. A probléma mégis az, hogy a lehetséges konverziók száma végtelen. Így egyszerűen, az olvasó változtatása nélkül kell az új átalakítást megadni.
Egy megoldás, ha az RTFReader osztályt egy más szövegmegjelenítésre konvertáló TextConverter objektummal állítjuk be. Amikor az RTFReader elemzi az RTF dokumentumot, a TextConvertert használja az átalakítás végrehajtására. Amikor az RTFReader felismer egy RTF tokent (sima szöveget vagy RTF vezérlő szót), kiad egy kérelmet a TextConverter-nek, hogy alakítsa át az adott tokent. A TextConverter objektumok felelnek az adatkonverzióért és a token egy bizonyos megjelenítési formátumáért.
A TextConverter alosztályai specializálódhatnak különböző konverziókra és formátumokra. Például a az ASCIIConverter elutasíthat minden konverziós felkérést, kivéve a sima szövegeseket. A TeXConverter megvalósíthatja azokat a műveleteket, amelyek a TeX formátumban való, a szöveg minden stílusinformációját tartalmazó megjelenítésre vonatkozó kérelmekkel kapcsolatosak. A TextWidgetConverter olyan felhasználói felületet hozhat létre, amivel a felhasználó láthatja és szerkesztheti a szöveget.
Mindegyik konvertáló osztály-típus tartalmazza az összetett objektumok létrehozásához és összeállításához szükséges mechanizmusokat, és ezeket egy absztrakt interfész mögé rejti. Az átalakító független az olvasótól, amely az RTF dokumentum elemzéséért felelős.
A Builder minta magába foglalja mindezen kapcsolatokat. A mintában minden konverter osztályt builder-nek, és minden olvasót director-nak hívnak. A példát alkalmazva, a Builder minta elkülöníti a szöveges formátumot értelmező algoritmust (ez az, ami az RTF dokumentumokat elemezi) az átalakított formátum létrehozásától és megjelenítésétől. Lehetővé teszi számunkra, hogy az RTFReader elemző algoritmusát újra felhasználjuk különböző szövegmegjelenítés létrehozására RTF dokumentumokból – csak más TextConverter alosztályt kell beállítani az RTFReader számára.
Akkor alkalmazzuk a Builder mintát, ha
- Az összetett objektum létrehozási algoritmusának függetlennek kell lennie az objektumot felépítő részektől és azok összeállítási módjától.
- A létrehozási folyamatnak lehetővé kell tennie a létrehozott objektum különböző megjelenítését.
- Builder (TextConverter) meghatározza a Product objektum létrehozására szolgáló absztrakt interfészt
- ConcreteBuilder (ASCIIConverter, TeXConverter, TextWidgetConverter) a Builder interfészt megvalósításánál felépíti és összeállítja a termék részeit. Definiálja és nyomon követi az általa készített megjelenítési módokat. Interfészt biztosít a termék beolvasásához (pl.: GetASCIIText, GetTextWidget)
- Director (RTFReader) a Builder interfész használatával létrehoz egy objektumot.
- Product (ASCIIText, TeXText, TextWidget) a felépítendő összetett objektumot képviseli. ConcreteBuilder felépíti a termék belső ábrázolását és definiálja az összeállítási folyamatokat. Tartalmazza az alkotó elemeket defináló osztályokat, beleértve a részek összeállítására szolgáló interfészeket.
- A kliens létrehozza a Director objektumot és beállítja a kívánt Builder objektummal.
- A Director értesíti a builder-t, ha egy objektum részét fel kell építeni.
- A Builder kezeli a dircetor-tól érkező kérvényeket és a részeket ad a product-hoz.
- A kliens elkéri a product-ot a builder-től.
- Lehetővé teszi a termék belső ábrázolásának a megváltoztatását. A Builder objektum a director számára egy absztrakt interfészt biztosít a termék felépítéséhez. Az interfész lehetővé teszi a builder-nek, hogy elrejtse a termék ábrázolását és belső felépítését. Elrejti a termék összeállításának módját is. Mivel a termék felépítése egy absztrakt interfészen keresztül történik, elég a termék belső ábrázolását megváltoztatni egy új builder típus definiálásához.
- Elszigeteli a felépítési és az összeállítási kódot. A Builder minta a modularitást az összetett objektum felépítésének és megjelenítésének az egységbe zárásával javítja. A kliensnek nem kell tudnia semmit a termék belső szerkezetét definiáló osztályokról; ilyen osztályok nem jelennek meg a Builder interfészében.
- Az építési folyamat finomabb vezérlését teszi lehetővé. Azoktól a létrehozási mintáktól eltérően, amelyek egy lépésben építik fel a terméket, a Builder minta lépésről lépésre építi fel a terméket a director felügyelete mellett. Csak akkor veszi át a director a terméket a builder-től, ha az elkészült vele. Emiatt a Builder interfész jobban tükrözi a termék felépítésének folyamatát, mint a többi létrehozási minta. Finomabb vezérlést tesz lehetővé az építési folyamatokon és ennek következtében a végső termék belső szerkezetén.
- Összeállítási és építési interfész. A Builder-ek termékeiket lépésről lépésre készítik el. Emiatt a Builder osztály interfésznek elég általánosnak kell lennie, hogy lehetővé tegye mindenfajta konkrét builder-nek a termékek létrehozását. A fő tervezési probléma az építési- és összeállítási folyamatok modellje. Azok a modellek megfelelőek, amelyek a létrehozási kérelmek eredményeit egyszerűen hozzácsatolják a termékhez.
- Miért nem absztrakt osztályokat használunk a termékeknél? Általában a konkrét builder-ek termékei annyira eltérnek a reprezentációjukban, hogy csak keveset nyerünk azzal, ha egy általános szülőosztályt adunk a különböző termékekhez. Mivel rendszerint a kliens a megfelelő konkrét builder-rel állítja be a director-t, ezért tudja, hogy a Builder melyik konkrét alosztálya van használatban, és ennek megfelelően kezeli a termékeket.
- Üres metódusok alapértelmezésként a Builderben. Üres metódusokat definiálunk, hogy a kliensek csak azokat a műveleteket bírálják felül, amelyekben érdekeltek.
A kódban szereplő osztályok:
- Builder: VehicleBuilder
- ConcreteBuilder: MotorCycleBuilder, CarBuilder, ScooterBuilder
- Director: Shop
- Product: Vehicle
// Builder pattern -- Real World exampleEredmény:
using System;
using System.Collections.Generic;
namespace Builder
{
///
/// Builder Design Pattern.
///
public class MainApp
{
///
/// Entry point into console application.
///
public static void Main()
{
VehicleBuilder builder;
// Create shop with vehicle builders
Shop shop = new Shop();
// Construct and display vehicles
builder = new ScooterBuilder();
shop.Construct(builder);
builder.Vehicle.Show();
builder = new CarBuilder();
shop.Construct(builder);
builder.Vehicle.Show();
builder = new MotorCycleBuilder();
shop.Construct(builder);
builder.Vehicle.Show();
// Wait for user
Console.ReadKey();
}
}
///
/// The 'Director' class
///
class Shop
{
// Builder uses a complex series of steps
public void Construct(VehicleBuilder vehicleBuilder)
{
vehicleBuilder.BuildFrame();
vehicleBuilder.BuildEngine();
vehicleBuilder.BuildWheels();
vehicleBuilder.BuildDoors();
}
}
///
/// The 'Builder' abstract class
///
abstract class VehicleBuilder
{
protected Vehicle vehicle;
// Gets vehicle instance
public Vehicle Vehicle
{
get { return vehicle; }
}
// Abstract build methods
public abstract void BuildFrame();
public abstract void BuildEngine();
public abstract void BuildWheels();
public abstract void BuildDoors();
}
///
/// The 'ConcreteBuilder1' class
///
class MotorCycleBuilder : VehicleBuilder
{
public MotorCycleBuilder()
{
vehicle = new Vehicle("MotorCycle");
}
public override void BuildFrame()
{
vehicle["frame"] = "MotorCycle Frame";
}
public override void BuildEngine()
{
vehicle["engine"] = "500 cc";
}
public override void BuildWheels()
{
vehicle["wheels"] = "2";
}
public override void BuildDoors()
{
vehicle["doors"] = "0";
}
}
///
/// The 'ConcreteBuilder2' class
///
class CarBuilder : VehicleBuilder
{
public CarBuilder()
{
vehicle = new Vehicle("Car");
}
public override void BuildFrame()
{
vehicle["frame"] = "Car Frame";
}
public override void BuildEngine()
{
vehicle["engine"] = "2500 cc";
}
public override void BuildWheels()
{
vehicle["wheels"] = "4";
}
public override void BuildDoors()
{
vehicle["doors"] = "4";
}
}
///
/// The 'ConcreteBuilder3' class
///
class ScooterBuilder : VehicleBuilder
{
public ScooterBuilder()
{
vehicle = new Vehicle("Scooter");
}
public override void BuildFrame()
{
vehicle["frame"] = "Scooter Frame";
}
public override void BuildEngine()
{
vehicle["engine"] = "50 cc";
}
public override void BuildWheels()
{
vehicle["wheels"] = "2";
}
public override void BuildDoors()
{
vehicle["doors"] = "0";
}
}
///
/// The 'Product' class
///
class Vehicle
{
private string _vehicleType;
private Dictionary_parts = new Dictionary ();
// Constructor
public Vehicle(string vehicleType)
{
this._vehicleType = vehicleType;
}
// Indexer
public string this[string key]
{
get { return _parts[key]; }
set { _parts[key] = value; }
}
public void Show()
{
Console.WriteLine("\n---------------------------");
Console.WriteLine("Vehicle Type: {0}", _vehicleType);
Console.WriteLine(" Frame : {0}", _parts["frame"]);
Console.WriteLine(" Engine : {0}", _parts["engine"]);
Console.WriteLine(" #Wheels: {0}", _parts["wheels"]);
Console.WriteLine(" #Doors : {0}", _parts["doors"]);
}
}
}
2011. január 23., vasárnap
The Secret of Monkey Island: Végigjátszás (IV.)
Az utolsó rész ott kezdődik, ahol az első véget ért: Mélée Island? mólóján. Guybrush egészen megkönnyebbült, hogy megszabadult szedettvedett társaságától. Aztán eszébe jut, hogy meg kellene állítani az esküvőt, még mielőtt nem késő és vidáman elszalad a templom felé. Egy másodperc múlva kevésbé vidáman vissza is szalad, mert egy szellem állja útját. Mindegy mit mondunk a szellemnek - mondjuk neki, hogy finom eladó szájvizünk van. A szellem csak akkor hajlandó venni, ha mentolos ízesítésű (csak azt szereti). Ennek örömére Guybrush jól lespricceli az antiszellem-létyóval. Egész jól működik... Szabad az út a templom felé. A következő sarkon egy másik szellem áll őrt - vele hosszas és elmés beszélgetést folytathatunk a szellemlét kérdéseiről (a végén úgyis lelocsoljuk), de rövidebb, ha a házon át levágjuk az utat.
2011. január 14., péntek
Gyártó függvény(Factory Method)
class CreatorEnnek lényege a megfelelő objektumok létrehozás anélkül, hogy annak részleteivel foglalkozni kellene egy magasabb absztrakciós szinten.where T : new()
{
T Create()
{
return Activator.CreateInstance();
}
}
The Secret of Monkey Island: Végigjátszás (III.)
Harmadik rész, a Majom Sziget
A leszállás még mindig nem teljesen tökéletes: főhősünk már megint fejjel érkezett célba (a tengerpart homokjába) és a kilövés mintha lángra gyújtotta volna nadrágjának hátulsó részét. Míg mi a homokban tekergünk amatőr struccként, egy majom kerül elő valahonnan és érdeklődve figyeli, hogy mit művelünk. A látottakhoz mindössze annyit tud hozzáfűzni, hogy "ook! eek!" - aztán távozik a dzsungelbe. Nemsokára egy újabb emberszabású figura érkezik.
- Toothrot: Hi, Herman Toothrot vagyok. (válaszra vár, aztán folytatja:) Ne is zavartasd magad azzal, hogy visszaköszönsz. Már 20 éve várok arra, hogy civilizált emberrel beszélhessek. Egyébként javaslom, hogy oltsd el azt a tüzet a fenekeden, mert még valaki megsérül tőle...
- "Rendkívüli népgyűlés szerda este! Meg kell vitatnunk, hogy az ördögi LeChuck szellemkalóz beköltözése a Majomfejbe milyen hatással van a környezetünkre és a turistaforgalomra! Monkey Island? összes kannibáljának megjelenésére számítunk!"
A sziget helyszínei közötti közlekedés hasonlít a Mélée Island?-en tapasztaltakhoz. Rögtön a tengerpart mellett rábukkanunk az előbbi majomra, amiről kiderül, hogy rendkívül éhes. "Mit eszik egy majom?" - tehetnénk fel a költői kérdést, de mivel tudjuk, inkább odaadjuk neki a hajózási szaktanácsadókat. Miután rájöttünk, hogy az nem ízlik neki, inkább banánt adunk neki. Azt villámgyorsan eltünteti, és érdeklődve figyeli a folytatást - sajnos az éhsége egy cseppet sem csillapult. Na nem baj, majd később felhizlaljuk. Továbbhaladva a sziget belseje felé egy szakadékba (CRACK) botlunk. A függőleges sziklafalon kissé körülményes lenne a lejutás, pedig ha egy kicsit vizsgálódunk, akkor a szakadék alján egy pár evezőt pillanthatunk meg. Talán némi kötélre volna szükségünk...
A szigetet egy kelet-nyugat irányba húzódó hegység szeli ketté, amely csak egyetlen helyen szakad meg: itt egy folyó folyik rajta keresztül. A folyó annak idején több ágból állt, de az egyik medre teljesen ki van száradva. Mihelyt elsétáltunk a folyóelágazáshoz (RIVER FORK), azt is megtudjuk miért: egy mesterséges gát zárja el. A folyón átívelő híd előtti sziklán egy újabb papírdarab található:
- "LeChuck szellemkalóznak.
Ismételten fel kell kérnünk Önt, hogy korlátozza éjszakai tevékenységét a Szent Majomfej területén! Néhány ember ugyanis szeretne aludni! Próbálja csökkenteni a zajszintet!
Monkey Island? kannibáljai
U.I: Láttuk ám, amikor azt a kendős nőt levitte magával!"
- "Monkey Island? kannibáljaihoz!
Nem érdekel, hogy imádkoztok a Majomfej előtt, ami az otthonom és hadműveleteim titkos bázisaként szolgál, de tartózkodjatok azon szokásotoktól, hogy a piszkos bálványaitokat a verandám előtt hagyjátok. Továbbá legyetek szívesek nem belépni a Majomfejbe!
LeChuck, sz.k."
Egyből el is látogathatunk oda (a sziget északnyugati csücskében fekszik). Itt rögtön több érdekes dolog is megüti a szemünket: elsősorban a sarokban heverő kötél (PICK UP ROPE). Másodsorban egy távcső (PICK UP SPYGLASS). Harmadsorban pedig az a rozsdás ágyú, ami valószínűleg már elég régóta használaton kívül van. Egy ágyú - de sehol egy fazék! Mivel ettől bosszús hangulatba kerülünk, úgy döntünk, hogy felborítjuk az ágyút (PUSH CANNON). Mihelyt összedől, megjelenik Toothrot is, aki először az után érdeklődik, hogy hova lett a távcsöve, aztán azon átkozódik, hogy mihelyt kiteszi innen a lábát, rögtön megjelenik valaki, aki összepiszkolja a padlóját... Ha beszélgetünk vele, akkor elmeséli a már százszor hallott történetet a csimpánzok vezette hajóról - ő küldte őket Mélée Island?-re, hogy segítséget hozzanak neki. A sziget lakosságáról annyit tud mondani, hogy ő az egyetlen civilizált ember a szigeten. Van még egy bennszülött törzs is, akik gyűjtögetnek és vadászgatnak (FEJvadászgatnak), de a kannibálok nem veszélyesek. Mindaddig, míg az ember kölcsön nem ad nekik valamit, ami például Toothrot banánszedőjével is történt. Toothrot meg addig nem adja vissza a kannibálok kulcsát a Majomfejhez, amíg vissza nem kapja az ő drága banánszedőjét...
Küldetésünkről elárulhatunk neki annyit, hogy azért érkeztünk ide, hogy megmentsünk valakit. Toothrot buzgón helyesel: ő az, akit meg kell menteni - de miért nem jöttünk egy kicsit korábban? Mivel szervezetünk esetleg megsínyli a hosszabb beszélgetést ezzel a figurával, inkább búcsúzzunk el tőle és fordítsuk a figyelmünket a földön heverő dolgokra: némi puskapor és egy ágyúgolyó kerül hozzánk (PICK UP GUNPOWDER és CANNONBAL). Ezzel a felszereléssel vissza is sétálhatunk a folyóelágazásig, ahol meg fogjuk szüntetni a gátat. Először is tegyük be a gát kövei közé a puskaport (USE GUNPOWDER WITH DAM). Most meg kellene gyújtani valamivel... Szerencsére van nálunk egy kovakő, amit valami keményebb tárgyon végighúzva elég nagy szikrát csiholhatunk. Az ágyúgolyó pedig elég kemény tárgy... (USE FLINT WITH CANNONBALL) Guybrush rémült kiáltással menekül a kitörő víz elől, de még idejében sikerül kimenekülnie a mederből. A víz pedig szépen feltölti a kiszáradt tavat a folyóág végén... Az akasztott embert tartó tuskót a víz felemelte és a hulla szépen leereszkedett. Undorunkat leküzdve szépen kihalászhatjuk a kezei közül a kötelet (PICK UP ROPE).
Most már két kötél boldog tulajdonosaként visszamehetünk a szakadékhoz, ahol a két kötelet a sziklafal két pontján USE-olva leeresz kedhetünk a szakadék fenekére és felvehetjük az evezőket (PICK UP OARS). Most, hogy már van evezőnk, rögtön vízitúrára is indulhatunk a parton álldogáló csónakkal (USE OARS WITH ROWBOAT). Csónakkal megközelíthető a sziget északi része, ahol a kannibálok faluja helyezkedik el. Odabent minden teljesen csendesnek tűnik - sehol egy teremtett lélek. A gyanakvó kalandor azonban végigvizsgálja az összes kunyhót. Az első üres. A második teljesen üres. A harmadik magasan van, de Guybrush fogadni merne rá, hogy üres. A negyedik a legüresebb kunyhó a világon. Az ötödikről annyit tudunk meg, hogy ha minden igaz, a szótárban az "üres" szó mellett ennek a kunyhónak a képe volt az illusztráció... Ezek után egészen felüdülésnek hat, hogy a hatodik kunyhó be van zárva. Egy tehát minden figyelmünket a hatalmas kőbálványra fordíthatjuk: Guybrush csapdától tartva nem akar bemenni - ellenben az előtte levő, gyümölcsáldozatot tartalmazó tálból szívesen elemel két banánt (PICK UP BANANA). Na, ezt elvisszük a mi derék, éhező majmunknak...
Azaz csak vinnénk: mihelyt kifelé indulnánk, három népviseletbe öltözött kannibál állja el az utat. "Mondd csak, barátom, az egy banán ott a zsebedben vagy ennyire örülsz, hogy láthatsz bennünket?" - érdeklődik az első. Az első két válaszra a bennszülöttek hagynak nekünk valami esélyt: ha adunk nekik valamit, amit felajánlhatnak a Nagy Majomfejnek, akkor hajlandóak bennünket meghagyni jelenlegi megfőzetlen állapotunkban. Meg lehet próbálni esetleg beugratni őket holmi hátuk mögött megjelenő háromfejű majomra hivatkozva (Look behind you...), de csak majdnem dőlnek be a trükknek. Pedig mihelyt kimondtuk, tényleg megjelenik a hátuk mögött egy háromfejű majom... A vége mindenképpen az, hogy bekísérnek bennünket a zárt kunyhóba. (Valószínűleg ott tárolják a nyers élelmiszert - CoVboy) Kívülről két lándzsát is az ajtónak támasztanak, hogy elejét vegyék az ajtónyitogatási kísérleteknek. Ez a kunyhó nem üres: itt van például többek között Toothrot banánszedője is, amit most magunkhoz veszünk (PICK UP BANANA PICKER). A földön egy koponya hever - ki tudja, hátha jó lesz még valamire! (PICK UP SKULL) Alatta egy meglazult padlódeszkát találunk, amelyet kinyitva már nyitva is áll a menekülés útja. Sajnos, van egy kis bökkenő is: a banánszedő nem fér be a nyíláson, tehát azt kénytelenek vagyunk itthagyni.
Míg a bennszülöttek a falu főterén vadul vitatkoznak Guybrush elkészítésének módozatain, a vacsora hátul szépen kioson faluból... (Aki akar egy kicsit szórakozni, az nekiállhat idegesíteni a bennszülötteket: menjünk vissza megint a faluba és fogassuk el magunkat. A főnök valószínűleg tehetséges mágus is: már előre tudta, hogy a banántolvaj visszatér a tett elkövetésének színhelyére - a mögötte álló pedig azt hajtogatja, hogy sokkal jobb lenne azonnal megenni bennünket. Rövid vita kezdődik Guybrush koleszteroltartalmáról, aztán megint bekísérnek a kunyhóba, de a biztonság kedvéért most már be is deszkázzák az ajtót. Harmadszorra már mint ügyes kis menekülőművészt köszöntenek bennünket és a kunyhó ajtajára hatalmas láncok is kerülnek...)
Csónakázzunk vissza a banánokkal a sziget déli részére, keressük meg a majmot és adjuk oda neki mind a kettőt. Ezeket is villámgyorsan elnyeli, de még mindig nem tűnik jóllakottnak a drága... Világos, hogy potenciális banánbeszerzőhelynek a parton álló banánfa számít - de arról talán csak a banánszedővel tudnánk szüretelni (az meg ott maradt a kannibálok kunyhójában). Így tehát a banánszedésnek egy teljesen más módozatát fogjuk választani.
Sétáljunk el a RIVER FORK-hoz, ahol a túlparton emelkedő sziklafalon egy lépcső vezet felfelé. A hatalmas szikla aljában valami egészen furcsa tákolmányt látunk: egy középen megtámasztott deszka egyik végén egy nagy szikla pihen - mintha valami katapult-szerűség lenne... Mellette természetesen egy MEMO-t találunk, rajta a következő szöveggel:
- "Monkey Island? kannibáljainak!
Ne mozdítsátok el a szerkezetet. Pontosan be van állítva.
Herman Toothrot"
Természetesen a hajónkat, ami villámgyorsan el is süllyed. Így tehát mielőtt még felmásznánk ide, egy kicsit módosítunk a katapult irányzékán (kétszer PULL PRIMITIVE ART). Az így beállított katapulttal történő lövés pontosan a banánfát találja telibe! Miután visszamásztunk a katapulthoz, mindenki nagy örömére egy újabb MEMO tűnik fel:
- "Mr. Toothrot!
Kérjük távolítsa el innen ezt a veszélyes szerkezetet! Citromfej véletlenül rápottyantott egy sziklát a felette levő szirtről és majdnem elsüllyesztett egy erre járó hajót!
A kannibálok"
A tisztás elején egy tábla fogad bennünket:
- "MAGÁNTERÜLET!
Bálványimádni szabad, de a Majomfejbe belépni nem!
LeChuck"
Amikor a kannibálok lekapcsolnak bennünket, feleljük nekik az első vagy a második választ és amikor várják, hogy mivel akarjuk megváltani a szabadságunkat, adjuk oda nekik a kis bálványt (GIVE LITTLE WIMPY IDOL TO CANNIBALS).
- - Törzsfőnök: Hoppá! Hát ez igazán nagyszerű! Citromfej! Ezt nézd meg!
- Citromfej (megvizsgálja): Hát ez tényleg nagyon szép - akárcsak az enyimek. És egyszerű - akárcsak az enyimek. És kicsi is - akárcsak az ennyimek. Nahát! Rá van írva, hogy Citromfej csinálta - akárcsak az enyimeken!
- Törzsfőnök: Ezt már igazán elvihetjük a Majomnak. Köszönjük neked a nagyszerű ajándékot. Bármikor szükséged van bármire Monkey Island?-en, csak nyugodtan gyere el hozzánk...
A szeleburdi játékos most hanyatt-homlok rohan a Majomhoz, hogy a kulccsal végre bejuthasson - aztán később majd meglepődik, amikor jól eltéved a labirintusban. A kannibálok felajánlották a segítségüket bármiben - miért ne használnánk ki? Tehát miután megkaptuk a kulcsot, menjünk ki a faluból és rögtön vissza. A három barátságos emberevő rögtön elősereglik fogadásunkra:
- - Kannibálok: Csak nem azért jöttél vissza, hogy lerójuk tartozásunkat a gyönyörű adományodért?
- Guybrush: Hát éppenséggel volna valami...(Well, actually...)
- Kannibálok: Mi az?
- Guybrush: Tulajdonképpen keresek valakit.(I'm looking for somebody)
- Kannibálok: Itt? Monkey Island?-en? Mi vagyunk az egyetlen nép, akik itt élünk? Az egyetlen civilizált nép.
- Guybrush: Akkor helyben is vagyunk. Az emberek, akiket keresek, nem élnek.(That's okay...)
- Kannibálok: Ja, hát AZOKRA a fickókra gondolsz? Már hónapok óta nyaggatnak bennünket: itt zörögnek körbe-körbe az idióta szellemhajóikkal... De mi már csak úgy vagyunk a kísértetekkel, hogy megfőzzük a mi kis varázsitalunkat és semmi félnivalónk tőlük.
- Guybrush: Akkor miért nem csináljátok most is ezt?(So why don't...)
- Kannibálok: A fő összetevője ennek a főzetnek egy nagyon ritka gyökér. Olyannyira, hogy csak egyetlen van belőle. Mindig csak egy kicsit szoktunk elhasználni, de most LeChuck ellopta tőlünk az egészet!
- Guybrush: Hol rejtőzik?
- Kannibálok: Van itt egy pokoli hely a sziget alatt, a katakombákon túl. A borzalmakat arrafelé minden magában hordozza... A turisták is órákig szoktak sorba állni, hogy láthassák.
- Guybrush: Na és, mi történt? A KÖJÁL bezáratta?(What happened...)
- Kannibálok: Nem, elvesztettük a kulcsot a Majomfejhez. Ellopták! Kölcsönadtuk Toothrotnak, de míg vissza nem hozza, addig a biztonság kedvéért magunknál tartottuk a banánszedőjét.
- Guybrush: Elmegyek megkeresni LeChuckot és visszaszerzem nektek a gyökeret!(I'm off to find...)
- Kannibálok: Hm, hát ez nem lesz túl könnyű. LeChuckot keresni nagyon veszélyes és sosem találod meg anélkül a... Hé!
- Guybrush: Mi? Miről van szó?
- Kannibálok: Navigatorszki fejecski nélkülecski.
- Guybrush: Micski vancski azzalacski fejecskivel?(What's the...)
- Kannibálok: A fenébe! Ez érti a mi bennszülött dialektusunkat! Hát annyit elmondhatok róla, hogy van egy fejünk, ami egy navigációs szerszám. Valamikor egy navigátoron volt... Mágikus úton életben tartottuk és útba igazít bennünket a katakombákban. Sajnos nem adhatjuk neked, mert csak egy van és az a mienk. Nem baj, cserébe azért, hogy nekünk adtad a bálványt, bármikor eljöhetsz és megnézheted a Majom kertjében.
Menjünk vissza tehát a Majomfejhez. Mivel a kulcs úgy néz ki, mint egy hatalmas fülpiszkáló, logikus, hogy a Majom fülénél fogjuk USE-olni. Erre a majom eltátja a száját és egy lépcső jelenik meg benne. Odabent egyirányú az út egészen a katakombákig, ami egy elég kellemetlen útvesztő. Amikor beléptünk húzzuk elő a navigátor fejét (USE HEAD OF NAVIGATOR) és mindig pillantsunk rá: minden lépésünknél közölni fogja, hogy merre kellene mennünk (néha poénkodik és azt mondja, hogy egy kicsit megzavarodott). Így nemsokára elérjük a szellemhajót.
A fedélzetén 4 szellemkalóz mulatozik: hárman zenélgetnek, a kapitány csicskája pedig a fejét hajigálja ide-oda. Amikor a fedélzetre lépünk, azonnal odaszalad hozzánk. Mondhatunk valamit neki (kérdezzük meg mondjuk, hogy "Ez a Lido Fedélzet?"), de úgyis az a vége, hogy Guybrush ijedt sikollyal leszalad a hajóról. Elfelejtettük felvenni a navigátor nyakláncát, ami láthatatlanná tesz bennünket a szellemek előtt...
A navigátor nem nagyon akar megválni a láncától, de ha szépen kérjük (például "cukorral a tetején") vagy megígérjük neki, hogy bevágjuk a lávába, akkor hajlandó belátni, hogy nincs szüksége nyakláncra, amikor nincs is válla. A nyakláncot egyből vegyük is fel magunkra (USE NECKLACE ON NAVIGATOR) és így a hajón láthatatlan emberként fogunk ide-oda mászkálni.
A fedélzetről balra nyíló ajtó vezet LeChuck kabinjába. Barátunk szokás szerint az ablaknál bámul kifelé, de ha túl közel merészkednénk hozzá, azonnal visszakerget az ajtó elé. Pedig oly hívogatóan bámul ránk az a kulcs a falról!... Így tehát kénytelenek leszünk használatba venni a jó öreg Stan iránytűjét (USE MAGNETIC COMPASS WITH KEY). Az erős mágnes hatására a kulcs szépen belebeg a tárgyaink sorába.
A fedélzetről jobbra nyíló ajtó rettenetesen nyekereg és a csicska állandóan odaszalad becsukni - így tehát az utunk a fedélközbe vezet tovább. A legénységi szállásra érkezünk, ahol egy szellemkalóz hortyog részegen, de még álmában is vadul magához öleli a grogosbutykosát, ha valaki megközelíti.
A következő szobában néhány szellemcsirke és szellemmalac hizlalja magát, továbbá van itt egy erősen világító láda is, amelyben azt a bizonyos gyökeret tárolják. Sajnos a láda zárva van - csak valamilyen szerszám segítségével tudjuk kinyitni. Próbáljunk megfogni egy csirkét (PICK UP CHICKEN). Nem nagyon sikerült: mindössze egy tolla maradt a kezünkben. Nem baj, pont arra van szüksége az alvónak! Sétáljunk tehát vissza a szomszéd szobában hortyogó barátunkhoz és csiklandozzuk meg a talpát a csirketollal. Erre hatalmasat ugrik és kiejti a kezéből a grogosbutykost (PICK UP JUG O' GROG). Az állatkáktól egy csapóajtó is vezet tovább lefelé, de sajnos ez is zárva van. A zárjába véletlenül pont passzol a kapitánytól ellopott kulcs (USE KEY ON HATCH). A csapóajtó a raktárba vezet, ahol egy csomó patkány heverészik szanaszét, de mindannyian tökrészegek. Kivéve azt, amelyik vad morgással ránktámad, ha a raktár hátsó részei felé indulnánk. Természetesen őt is ugyanolyan állapotba ringatjuk, mint amilyenben a többiek leledzenek: öntsünk a tálkájába egy kis grogot (USE JUG O' GROG WITH ON DISH). A harcias patkány buzgón fellefetyeli az egészet és hamarosan ő is részegen hortyog a padlón. Mi pedig megnézhetjük mit rejt a hátul álló üst. Lisztet. Miután magunkhoz vettünk egy adagot belőle, sétáljunk vissza a fedélzetre, mert a nyikorgó ajtót bekenve vele, csöndben belopakodhatunk a dutyihoz. A cella előtt egy újabb szellemkalóz húzza a lóbőrt és Guybrushnak nem nagyon akarózik felébresztenie bármilyen antiszellem-kotyvalék nélkül. Egyébként is a falon lógó szerszámkészletért jöttünk (PICK UP GHOST TOOLS). A szerszámokkal menjünk vissza a gyökeret rejtő ládához és nyissuk ki velük (USE GHOST TOOLS WITH GLOWING CRATE). Ott mosolyog benne a gyökér, amiért idejöttünk...
Miután nálunk van a gyökér, itt is hagyhatjuk a szellemhajót. Hál'Istennek a játék készítői a visszautat a kannibálok falujába megspórolták nekünk, nem kell egy csomót szenvedni visszafelé... A bennszülöttek csodálkozva látják, hogy tényleg megszereztük a gyökeret. Rögtön szaladnak is megfőzni a varázsitalukat. Mi addig beszélgethetünk a háromfejű majommal, ami ismét feltűnik a kunyhók közül. A majom ugyan nem válaszol, viszont buzgón elrágcsál egy banánt. Ennyi idő alatt elkészül a főzet is, amit a kannibálok egy szódásszifonban nyújtanak át. Használati utasítás: "Csak spricceld rá egy szellemre, aztán majd meglátod. Ha megmaradna valamennyi a löttyből, akkor vaníliafagylaltként is fogyasztható..." Mire visszaérünk a titkos rejtekhelyhez, LeChuck hajója eltűnik! Mindössze a csicskása szomorkodik a parton.
- - Guybrush: Hé!
- Csicska: Hé! Majdnem halálra rémítettél...
- Guybrush: Hová lett a hajó?(What happened...)
- Csicska: Mindenki elment az esküvőre.
- Guybrush: Miféle esküvőre?!(What wedding?)
- Csicska: LeChuck feleségül veszi Mélée Island? kormányzóját.
- Guybrush: MICSODA?! Hogy tehetik ezt velem? Hol lesz az esküvő?(Where is the wedding?)
- Csicska: Abban a szép kis templomban Mélée Island?-en.
- Guybrush: Óh, nem! Utánuk kell mennem és meg kell állítanom őket.(I've got to go...)
Elvont Gyár (Abstract Factory)
Akkor használjuk az Abstract Factory mintát, ha
- A rendszernek függetlennek kell lenni attól, hogyan hozza létre, állítja össze és jeleníti meg a termékeit.
- A rendszernek be kell állítania egyet a termékcsalád közül.
- Kapcsolódó termékobjektumok egy családját együttes használatra tervezték, és ezt a megszorítást ki kell kényszeríteni.
- Gondoskodni kell a termékek osztálykönyvtáráról, és csak az interfészüket fedhetjük fel, de a megvalósításukat nem.
- AbstractFactory: az absztrakt termékobjektumokat létrehozó interfészt deklarálja.
- ConcreteFactory: a konkrét termékobjektumok létrehozására szolgáló műveleteket implementálja.
- AbstractProduct: a termékobjektumok egy típusának interfészt deklarálja.
- ConcreteProduct: definiálja a létrehozandó termékobjektumot a megfelelő konkrét factory (gyár) mellett, implementálja az AbstractProduct interfészt.
- Client: csak az AbstractFactory és az AbstractProduct osztályok által deklarált interfészeket használja.
Az Abstract Factory mintának a következő előnyei és hátrányai vannak:
- Elszigeteli a konkrét osztályokat. Az Abstract Factory minta segít az alkalmazások által létrehozott objektumosztályok irányítását. Mivel a factory egységbe zárja a termékobjektum létrehozásának felelősségét és folyamatát, így elszigeteli a klienst az implementációs osztályoktól. A kliensek a példányokat saját absztrakt interfészükön át kezelik. A termékosztályok nevei elszigeteltek a konkrét factory implementációjában; azok nem jelennek meg a kliens kódjában.
- Megkönnyíti a termékcsaládok cseréjét. A konkrét factory osztálya egy alkalmazásban egyszer jelenik meg – ahol példányosítottuk. Ez megkönnyíti az alkalmazás által használt konkrét factory megváltoztatását. A különböző termék használatához csak a konkrét factory-t kell megváltoztatni. Mivel az absztrakt factory komplett termékcsaládokat készít, egyszere megváltozik az egész termékcsalád.
- Támogatja a termékek közti konzisztenciát. Amikor egy családon belül a termékobjektumokat együttműködésre tervezték, akkor fontos, hogy az alkalmazás egy időben csak egy családhoz tartozó objektumokat használjon. Az AbstractFactory ezt könnyen érvényesíti.
- Az új termékfajták támogatása nehézkes. Az absztrakt factory kibővítése újfajta termékek létrehozására nem könnyű. Azért mert az AbstractFactory interfész rögzíti a létrehozható termékek halmazát. Az újfajta termékek támogatásához ki kell bővíteni a factory interfészt, amihez meg kell változtatni az AbstractFactory osztályt és annak minden alosztályát.
- Factory-k mint Singleton-ok. Egy alkalmazásnak tipikusan csak egyetlen egy ConcreteFactroy példányra van szüksége termékcsaládonként. Így azokat általában legjobb Singleton segítségével implementálni.
- A termékek létrehozása. Az AbstractFactory csak a termékek létrehozására szolgálóinterfészt deklarálja. A ConcreteProduct alosztály végzi valójában a létrehozást. A legáltalánosabb megoldás, ha minden termékhez deklarálunk egy factory metódust. Amíg az implementáció egyszerű, addig minden egyes termékcsaládhoz szükség van egy konkrét factory alosztályra, még akkor is ha a termékcsaládok csak alig térnek el.
- Ha sok termékcsaládra van szükség, a konkrét factory implementálható a Prototype minta felhasználásával. A konkrét factory a családba tartozó minden termékhez külön tartozó prototípus példány segítségével inicializálható, és a prototípus klónozásával hozható létre új termék. A prototípus alapú megközelítés kiküszöböli, hogy minden egyes új termékcsaládnak új konkrét factory-ra lenne szüksége.
- ővíthető factory-k definiálása. Az AbstractFactory általában különböző műveleteket definiál az általa létrehozható minden termékfajtához. A termékek típusa a műveletek szignatúrájába van kódolva. Egy új terméktípus hozzáadása estén szükség van az AbstractFactory interfész és az összes tőle függő osztály megváltoztatására.
- Egy rugalmasabb, de kevésbé biztonságos kivitelezés, ha az objektumokat létrehozó műveleteket paraméterezzük. Ez a paraméter határozza meg a létrehozandó objektum típusát. Ez lehet egy osztályazonosító, egy egész szám, egy sztring, vagy bármi ami azonosíthatja a termék típusát. Ezzel a megközelítéssel, az AbstractFactory-nak csak egy egyszerű „Make” műveletre van szüksége, ami a létrehozandó objektum típusát jelző paraméterrel rendelkezik. Ezt a technikát használjuk a fent megbeszélt Prototype- és osztály-alapú absztrakt factory-kban.
class SpriteMint látható a Game osztályban már nem kell foglalkozni az egyes elemek részleteivel. A CreateLevel helyére el lehet képzelni egy olyan ciklus, ami egy file-ból tölti be a pályát. A másik trükk, hogy felhasználtuk az Egyke mintát is egyúttal.
{
public Sprite(int size, string textureName) { }
}
static class SpriteFactory
{
public static Sprite CreateBall()
{
return new Sprite(20, "ball.png");
}
public static Sprite CreateWall()
{
return new Sprite(100, "wall.jpg");
}
}
class Game
{
Sprite[,] map = new Sprite[10, 10];
public void CreateLevel()
{
map[0, 0] = SpriteFactory.CreateWall();
map[1, 0] = SpriteFactory.CreateWall();
map[1, 1] = SpriteFactory.CreateBall();
}
}
Mi van akkor, ha a pályaszerkesztővel több pályát is szeretnénk készíteni egységes jelöléssel? A wall az mindig W, a ball az pedig mindig B. Többféle világ is van, ahol a ball az lehet forest, vagy robo is. Nem szeretnénk átírni se az editort, se a pálya betöltőt, úgyhogy a gyárak körül kell változtatni. A következő példa már az Elvont gyárat mutatja be:
- AbstractFactory: IAbstractFactory
- ConcreteFactory: RobotSpriteFactory, ForestSpriteFactory
- Client: Game (CreateLevel)
using System;Látható, hogy a CreateLevel lényegében semmit nem változott. Ha több 100 elemet kell betölteni, akkor se történik változás, mindig a világnak megfelelő objektumok fognak betöltődni. Itt még pluszban az Egyke minta egyik C# változatát is felhasználtuk, hogy ne kelljen állandóan fölösleges objektumokat létrehozni.
namespace ConsoleApp
{
static class SingletonManagerwhere T : new()
{
static T instance = Activator.CreateInstance();
public static T Instance
{
get { return instance; }
}
}
class Sprite
{
public Sprite(int size, string textureName) { }
}
interface IAbstractFactory
{
Sprite CreateBall();
Sprite CreateWall();
}
class ForestSpriteFactory : IAbstractFactory
{
public Sprite CreateBall()
{
return new Sprite(20, "ball.png");
}
public Sprite CreateWall()
{
return new Sprite(100, "wall.jpg");
}
}
class RobotSpriteFactory : IAbstractFactory
{
public Sprite CreateBall()
{
return new Sprite(26, "roboBall.png");
}
public Sprite CreateWall()
{
return new Sprite(120, "roboWall.jpg");
}
}
class Game
{
Sprite[,] map = new Sprite[10, 10];
public void CreateLevel(IAbstractFactory factory)
{
map[0, 0] = factory.CreateWall();
map[1, 0] = factory.CreateWall();
map[1, 1] = factory.CreateBall();
}
}
static class Program
{
static void Main()
{
var forestGame = new Game();
forestGame.CreateLevel(SingletonManager.Instance);
var robotGame = new Game();
robotGame.CreateLevel(SingletonManager.Instance);
}
}
}
Az Abstact Factory osztályokat gyakran factory metódusokkal (gyártó függvényekkel) valósítják meg, de implementálhatóak Protoype használatával is.
Ünnepel az Nvidia: elkészült az egymilliárdodik GeForce chip
Az évek során aztán persze az Nvidia újabb és újabb chipeket dolgozott ki és dobott piacra, tavaly pedig már sajátmárkás kártyákkal is megjelent. Legújabb lapkakészlete, a GeForce 500-as sorozata több mint ezerszer akkora teljesítményre képes, mint a GeForce 256.
2011. január 12., szerda
HAL 9000
Boldog Születésnapot HAL!
2011. január 9., vasárnap
Alphabetical BubbleSort
private string[] AlphabeticalBubbleSort(string[] values)
{
int i = 0;
int j = 0;
string temp;
for (i = values.GetUpperBound(0); i >= 0; i--)
{
for (j = 0; j <= i; j++)
{
if (values[j].ToString().ToLower().Trim() > values[j + 1].ToString().ToLower().Trim())
{
//Swap values
temp = values[j].ToString();
values[j] = values[j + 1];
values[j + 1] = temp;
}
}
}
return values;
}
C# tömbök mesteri szinten (2)
Tételezzük fel, hogy egy táblázatot alkotó "jagged" tömb minden egyes sora kb. 4000 bájt méretű (figyelem, a méret a lényeg!). Ha ez a táblázat túl sok sorból áll, akkor minden esetben, amikor egy eltérő sor adataihoz hozzá szeretnénk férni, akkor a tábla/tömb és az állandó memória lapméretek miatt (mondjuk 4 KB) az operációs rendszernek úgynevezett memória-lapváltást kell végrehajtania. Másképp mondva hozzá kell férnie a tömbelem másik lapon lévő adataihoz. Vagyis a lenti példa szerint a belső ciklus miatt, minden tömbelemhez való hozzáférés újabb és újabb plusz memóriaműveletet (a már említett lapváltást) generál. Példa:
A fenti példa szerint tehát MAX_COLUMNS * MAX_ROWS darab memória-lapváltás történik, melyet mindenképp jó lenne kiküszöbölni, és erre az alábbi lehetőség áll a rendelkezésünkre.
for (int column = 0; column < MAX_COLUMNS; column++)
{
for (int row = 0; row < MAX_ROWS; row++)
{
table[row][column] = BlankTableElement();
}
}
Egyszerűen megcserélődött a két ciklus, vagyis ami eddig kívül volt az belül lesz és fordítva. Ebben az esetben is lesz memória-lapváltás, de már csak MAX_ROWS és nem MAX_COLUMNS * MAX_ROWS esetben. A teljesítménynövekedés feladattól és környezettől függően változhat, de bizonyos esetben, pl.: a második példa ciklusa akár 1000x előbb is befejeződhet, mint az első. Ha már a tömböknél tartunk... Az alábbi példa igaz, hogy a kód olvashatóságát rontja egy kissé, de teljesítmény szempontból, bizonyos helyzetekben rendkívül hatékony tud lenni (ez az úgynevezett „unrolling” művelet). Példa:
for (int row = 0; row < MAX_ROWS; row++)
{
for (int column = 0; column < MAX_COLUMNS; column++)
{
table[row][column] = BlankTableElement();
}
}
Ez egy egyszerű ciklus volt, ami egy „a” numerikus tömböt feltöltött az „i” index értékével. A fenti megoldás helyett, amennyiben lehetséges (nyilván nem mindig), legyen inkább egy másik megoldás…
i = 0;
while (i < count)
{
a[i] = i;
i = i + 1;
}
A lényeg az, hogy a tömbön belül nem egyesével, hanem fura módon kettesével léptetjük az „i” indexet, és minden iterációnál kitöltjük az aktuális, valamint az aktuális i + 1 tömbelemet (vagy más feladat esetén végrehajtunk valami más tömbműveletet). Páratlan számú iteráció esetén az utolsó elem kitöltésére csak a ciklus után, külön kerülhet sor. A teljesítménynövekedés környezettől függően változhat, ezért az alkalmazása előtt méréseket kell végezni. Ahol a teljesítmény különösen kritikus és fontos, ott a .NET menedzselt kód által nyújtott plusz szolgáltatások kikerülhetők, azaz elérhető, hogy a tömbök adata ne a referencia típusokra jellemző menedzselt halmon (heap), hanem az annál jóval gyorsabban hozzáférhető, és a szemégyűjtő Garbage Collector által nem inzultált vermen (stack) tárolódjon. Az imént említett tömbhasználat felturbozásához a stackalloc nevű C# utasítást kell használni (fordításkor a /unsafe opció szükséges). Ez a módszer csak egy dimenziós, 0 bázisú, érték típusú elemeket tartalmazó tömböknél működhet. Amikor a stackalloc használatban van, akkor a memória blokkok eléréséhez úgynevezett unsafe pointer-t alkalmaz a rendszer. Ezek a memóriaterületek az adott hatókör (pl.: egy metódus return utasítása) után automatikusan felszabadulnak. Példa:
i = 0;
while (i < count - 1)
{
a[i] = i;
a[i + 1] = i + 1;
i = i + 2;
}
if (i == count)
{
a[count - 1] = count - 1;
}
Minden téma végén megjegyzem, hogy ezeket a megoldások és példák természetesen nem az én fejemben születtek. Ahhoz, hogy az ember hozzájusson a fenti okosságokhoz, egyszerűen csak olvasni kell, méghozzá sokat. "Mert olvasni nem gyíkság..."
class StackallocSample
{
unsafe public static void ShowData(int* pArray)
{
for (int* ip = pArray; ip < (pArray+5); ip++)
{
Console.WriteLine("value {0} at address: {1}", *ip, (int)ip);
}
}
static void Main(string[] args)
{
unsafe
{
int* pArray= stackalloc int[5];
pArray[0] = 12;
pArray[1] = 34;
pArray[2] = 56;
pArray[3] = 78;
pArray[4] = 90;
ShowData(pArray);
}
}
}
A múltkori témák adták az ötletet arra nézve, hogy néhány további, teljesítménynövelésre buzdító javaslatot tegyek, de most inkább csak az iterációkra (ciklusokra) vonatkoztatva. A korábbi példákhoz nagyon hasonló eset az, amikor az egymásba ágyazott ciklusok önmagában álló teljesítményét vizsgáljuk. Az utasítások működési jellemzőjéből adódóan, a belső ciklus minden egyes iterációjának alkalmával a ciklusváltozót inicializálni kell, az összehasonlító logikai kifejezést értékelni kell, valamint ciklusváltozót is növelni kell.
A fenti példában kívül van a több, belül pedig a kevesebb iterációt végrehajtó ciklus. Ezesetben a ciklusváltozók menedzselése egészen pontosan 100 + (100 * 5) = 600 alkalommal hajtódik végre, ami kiélezett helyzetben tetemes időt vehet igénybe. Ilyenkor nincs más teendő, mint a külső, többször iteráló, illetve a belső, kevesebbszer iteráló ciklust egyszerűen felcserélni egymással.
for (int column = 0; column < 100; column++)
{
for (int row = 0; row < 5; row++ )
{
…
}
}
A javított változatban a ciklusváltozók menedzselése 5 + (5 * 100) = 505 alkalommal hajtódik végre, ami a 16%-kal kevesebb feladatot ró a működtető környezetre (ez utóbbi példa javára). Természetesen .NET esetén ez a példa picit erőltetett, mivel a JIT fordító számos optimalizálást már előre végre tud hajtani. A végső megvalósítás előtt ezesetben is érdemes méréseket végezni.
for (int row = 0; row < 5; row++ )
{
for (int column = 0; column < 100; column++)
{
…
}
}
Szintén ciklusok esetén jellemző az, amikor mondjuk egy metóduson belül lévő ciklusban végre kell hajtani bizonyos műveleteket, aztán később ugyanilyen cikluson belül egy másik műveletet. Ezesetben érdemes megvizsgálni annak a lehetőségét, hogy a két azonos feltételekkel rendelkező ciklust nem lehetne-e összevonni (ezek az úgynevezett „jamming” vagy „fusion” műveletek).
for (int i = 0; i <= 100; i++)
{
employeeName[i] = "";
}
// Itt most különféle egyéb utasításokat, műveleteket kell elképzelni…
for (int i = 0; i <= 100; i++)
{
employeeEarnings[i] = 0;
}
A fenti megoldás helyett, amennyiben ez lehetséges, legyen inkább összevonás…
A ciklusokon belüli összetett műveletek mértékét a lehető legkisebbre kell venni. Ez azt jelenti, hogy minden idő és erőforrásigényes utasítás esetén meg kell vizsgálni, hogy nem lehet-e azt kiemelni a cikluson kívülre.
for (int i = 0; i <= 100; i++)
{
employeeName[i] = "";
employeeEarnings[i] = 0;
}
Ha a „rates” objektum „CalculateDiscounts()” metódusa mondjuk adatbázis, vagy más erőforrásigényes műveletet hajt végre, aminek a végeredménye az adott időben ugyanaz, akkor érdemes kiemelni azért, hogy csak egyszer hajtódjon végre (tudom, hogy ezek elemi dolgok, de hátha olyasvalaki is olvassa, aki csak most kezdi a programozói pályáját). Tudom-tudom... ezek primitív dolgok, de akkor is.
for (int i = 0; i < rateCount; i++)
{
netRate[i] = baseRate[i] * rates.CalculateDiscounts();
}
Amennyiben egy cikluson belül már nincs értelme a további iterációnak, akkor gondoskodni kell az iteráció azonnali, vagy legalábbis a lehető leghamarabb történő befejezéséről. Minden további felesleges műveletet teljesítmény és erőforrás gazdálkodási okokból kerülni kell.
quantityDiscount = rates.CalculateDiscounts();
for (int i = 0; i < rateCount; i++)
{
netRate[i] = baseRate[i] * quantityDiscount;
}