2012. július 1., vasárnap

Bemelegítés #3

A bemelegítő posztsorozat utolsó felvonása, amelyben CodeNinja végre megeszi a borítóképen látható kódot. Ki hitte volna, hogy háromfogásos menünek bizonyul?

Emlékeztetőül a borítóképen látható kódrészletről beszélünk, és az első sor végéig jutottam a múltkori poszttal:
    
    public class CodeNinja : Warrior, ICoder
    {
        static private Color _color;
        static private Visibility _visibility;
 
        public Int32 Level { get; set; }
 
        static CodeNinja()
        {
            _color = Color.Black;
            _visibility = Visibility.Hidden;
        }
 
        public static CodeNinja CreateCodeNinja(Int32 level)
        {
            var ninja = new CodeNinja { Level = level };
            return ninja;
        }
    }

Az ominózus első sor után egy { (nyitó kapcsos zárójel áll). Ez a C#-ban a blokk nyitó jel, a blokkzáró - talán kitalálható - a záró a } (záró kapcsos zárójel) lesz. Ismerek olyanokat, akik szerint ennyi információ elég is egy programnyelv jóságának eldöntéséhez. Ez egy erősen fundamentalista  szemlélet, amihez nyilvánvaló C# rajongásom ellenére sem szívesen csatlakoznék. Inkább adnék egy útravalót a kódblokkokkal kapcsolatban. 
Mindig ki kell tenni a blokk határolókat, akkor is ha a szintaktika ezt nem követelné meg feltétlenül az adott helyen. Ez bőségesen megtérül majd, amikor egy utólagos kódmódosításkor logikai hibát vétenénk, mert tévesen értelmeznénk az egzaktul nem jelzett a kódhatárokat egy bonyolultabb vezérlési szekvencián belül. Szerencsére a Visual Studio különféle kódkiegészítő szolgáltatásai ebbe az irányba presszionálnak, hiszen kiteszik a blokkhatárolókat, és remélhetőleg nem akad oly elvetemült önsorsrontó, aki képes őket kitörölni... :-)
A két zárójel közt van maga az osztályunk. Először két privát tagváltozó, deklarációja következik:
    
        static private Color _color;
        static private Visibility _visibility;

A Color típusú _color és a Visibility típusú _visibility. A private egy hozzáférés módosító, amit az osztály kapcsán már kiveséztem. De itt ugyebár a tagra vonatkozik, és azt jelenti, hogy ezek a tagok csak a CodeNinja  osztály belsejében láthatók. Mivel a private egyben az alapértelmezett hozzáférés módosító az osztály tagjaira, ezért ha nem írtuk volna ki, akkor is ugyanazt jelentené. Én azonban mindig kiírom a hozzáférés módosítókat. Első ránézésre talán nincs sok értelme, de így olvasásánál majd arcon sikítja a résztvevőket. Az meg sosem árt, ha az ember órák óta a kódban bolyong.
De a private előtt ott van még egy  kulcsszó: static. Amikor egy osztályt példányosítunk, akkor létrejön az adott egyedet jelképező példány, erre az egyedre jellemző értékekkel az adattagokban. Azonban egy típusnak lehetnek olyan tulajdonságai is, amelyek nem egy adott egyedre vonatkoznak, hanem az összes ilyen típusú egyed esetében közös értéket vesznek fel. Na, pontosan erre használjuk a statikus adattagokat. Ezekből egyetlen közös példány lesz, amely az adott típusé, és az összes példány ezt használja.
Mivel senki nem jelentkezett a múltkori poszt után a leleplezéssel (talán a jutalom volt hihetetlen), ezért lelövöm én a poént. Itt van az a csúnya eltérés a Microsoftos kódolási konvencióktól. Mert a private tagokat egyszerűen camel case írjuk, és nem használunk prefixet. Ellenben a kódban minden private tag hivatkozásakor kiírjuk a this szócskát. Ez a  C#-ban mindig az adott kontextusban aktuális osztály példányát hivatkozza. Az aláhúzás egy korábbi konvenció maradványa, de benne van a kezemben még, és nem volt kedvem újra photoshopolni a képet.

A következő sor:
     
        public Int32 Level { get; set; }

Az objektum orientált programozásban az egységbezárás nevű alapelv egyik legfontosabb pilléreként tekintsünk erre a sorra. A háttérben megbújó lényeg, hogy egy osztály adattagjait sosem érjük el közvetlenül az osztályon kívülről (információ rejtés). Azokkal az adatokkal amik a külvilágra tartoznak, speciálisan járunk el, deklarálunk melléjük egy publikus láthatóságú field-et, amit property (tulajdonság) néven szokás illetni. Így írnánk ezt C#-ul:
     
        private int level;
        public int Level
        {
            get { return this.level; }
            set { this.level = value; }
        }

A level a privát adattag, a Level a property, amihez két különös metódus tartozik a setter és a getter. Ezek most csak az értéket közvetítik level felé, de persze ennél bonyolultabbak is lehetnének.
Csakhogy a C# 3.0 óta ilyet ember nem ír le. Azóta létezik ugyanis a rövidebb konstrukció, az úgynevezett automatikusan megvalósított tulajdonságok (Auto-Implemented Properties). Ez pedig pontosan azt eredményezi, amit a második hosszabb kód.
Még egy apróság: az int ugye ugyanaz mint az Int32. Bátran használjuk a C# beépített típusait, aki nem emlékezne kapásból, hogy mi mit jelent, annak itt egy táblázat.

Ami ezután következik, azt úgy hívják, hogy statikus konstruktor:
    
        static CodeNinja()
        {
            _color = Color.Black;
            _visibility = Visibility.Hidden;
        }

A statikus konstruktor egy nagyon érdekes lakója az objektum orientált állatkertnek. A konstruktor ugye az objektumok példányosításakor jut szerephez (egy új példány létrehozásakor fut), és lényegében a példány inicializálásáért felel. Az imént már szóltam pár szót a statikus adattagokról, melyek nem példányhoz, hanem a típushoz kötődnek. Ezek beállításáért a statikus konstruktor felel, amellyel kapcsolatban joggal vetődik fel a kérdés, hogy ez mikor fog meghívódni. Nos, vagy a típus első példányosítása előtt vagy mikor először hivatkozunk egy statikus tagot, hiszen ehhez nem kell példányosítanunk.
Tehát a fenti kód beállítja a CodeNinja típus közös tulajdonságaként, hogy a _color jellemző black legyen, míg a _visibility hidden. Ami minden CodeNinja példányra vonatkozni fog és éppen megfelel egy nindzsának.

Már csak egyetlen részlet maradt. Ez a pár sor itt:
    
        public static CodeNinja CreateCodeNinja(Int32 level)
        {
            var ninja = new CodeNinja { Level = level };
            return ninja;
        }

Ezt itt egy statikus metódus, tehát az osztály példányosítása nélkül is meghívhatjuk. Public, tehát ezt bárhonnan megtehetjük. Amúgy pedig egyfajta gyártó függvény (Factory Method), csak nincs külön osztályba csomagolva. A gyártó függvény egy igen ismert programtervezési minta (Design Pattern). A tervezési mintákról most csak annyit, hogy a programozás egy magasabb szintjét képviselik. Tökéletesen el lehet programozgatni anélkül is, hogy halvány fogalmad lenne bármely pattern-ről. Bár az azért egy szint után felvetődhet, hogy minek?
A fenti függvény nem csinál mást, mint kreál egy kódnindzsa példányt. És visszaadja azt. Egy valamire való gyártó függvénynek paraméterben meg szokás kapnia azokat az értékeket, amelyek egy példány inicilizálásához szükségeltetnek, esetünkben ez most az egy szem Level tulajdonságban kimerül.
A példányosítás a new operátorral történik, a mögötte látható formulát (a kapcsos zárójel, és ami benne van) úgy hívják, hogy objektum inicializáló (Object Initializer). Itt felsorolhatjuk azokat a tagokat, amelyeket inicializálni kívánunk, és megadhatjuk, az értéket, amit kapjanak. Ha valaki erről az előbb emlegetett gyártó függvény inicializáló képességére asszociálna, akkor teljes joggal teszi. Szép példája, ahogy egyes pattern-ek, vagy azok alapjait adó elgondolások a nyelvi elemeken keresztül beépülnek a C#-ba. Szerencsére a Microsoft a teljes fejlesztői keresztmetszetén erőlteti a minták használatát, megvalósítását, beépülését a fejlesztési folyamatokba. Amely egy igen dicséretes törekvés, Isten tartsa meg jó szokásukat.
Ezzel végére is értünk a bemelegítésnek. Innentől jöhetnek a komoly posztok... :-)

Nincsenek megjegyzések:

Megjegyzés küldése