Az Objective-C programozási nyelv

Tervezési minták megvalósításai

Observer

Observer tervezési minta

Rövid leírás

Olyan egy-több függőség megadása objektumok között amelyben ha egy objektum állapotot vált, akkor az összes tőle függő objektumot értesíteni és módosítani kell.

Felhasználhatóság

Résztvevők

Példa kód

A következő példa kód szemlélteti az Observer egy lehetséges megvalósítását Objective-C nyelven. AZ egyszerűség kedvéért, A megfigyelendő állapot esetünkben egy int változó értéke.

// observer.h #import <Foundation/Foundation.h> #define ABSTRACT ABSTRACT @interface Observer : NSObject - (void) Update ; @end ;

// observer.m #import "observer.h" @implementation Observer - (void) Update { ABSTRACT } @end ;

// subject.h #import <Foundation/Foundation.h> #import "observer.h" #define ABSTRACT ABSTRACT @interface Subject : NSObject { NSMutableArray * observers ; } - (id) init ; - (void) dealloc ; - (void) Attach : (Observer*) object ; - (void) Detach : (Observer*) object ; - (void) Notify ; @end ;

// subject.m #import "subject.h" @implementation Subject - (id) init ; { observers = [[ NSMutableArray alloc ] init ] ; return self ; } - (void) dealloc ; { [ observers release ]; [ super dealloc ]; } - (void) Attach : (Observer*) object { [ observers addObject: object ]; } - (void) Detach : (Observer*) object { [ observers removeObject: object ]; } - (void) Notify { NSEnumerator * enumerator = [observers objectEnumerator]; id observer; while ((observer = [enumerator nextObject]) != nil) { [ observer Update ]; } [ enumerator release ]; } @end ;

// concreteobserver.h #import <Foundation/Foundation.h> #import "observer.h" #import "concretesubject.h" @interface ConcreteObserver : Observer { ConcreteSubject * subject ; } - (id) initWithSubject: (ConcreteSubject*) object ; - (void) Update ; - (void) dealloc ; @end ;

// concreteobserver.m #import "concreteobserver.h" @implementation ConcreteObserver - (id) initWithSubject: (ConcreteSubject*) object ; { [ object retain ]; subject = object ; return self ; } - (void) Update { // here goes the acction wich will be performed on subject state change NSLog(@"the state changed to : %i", [subject getState]); } - (void) dealloc { [ subject release ] ; [ super dealloc ]; } @end ;

// concretesubject.h #import <Foundation/Foundation.h> #import "subject.h" @interface ConcreteSubject : Subject { int state ; } - (id) init ; - (int) getState ; - (void) setState : (int) new_state ; @end ;

// concretesubject.m #import "concretesubject.h" @implementation ConcreteSubject - (id) init { [super init] ; state = 42 ; return self ; } - (int) getState ; { return state ; } - (void) setState : (int) new_state ; { state = new_state ; [ self Notify ]; } @end ;

// application.h #import <Foundation/Foundation.h> @interface Application + (int) run ; @end

// application.m #import <Foundation/Foundation.h> #import "application.h" #import "concretesubject.h" #import "concreteobserver.h" @implementation Application + (int) run ; { NSAutoreleasePool * pool = [ NSAutoreleasePool new ] ; id S = [ [ ConcreteSubject alloc ] init ]; id O = [ [ ConcreteObserver alloc ] initWithSubject: S ]; [ S Attach: O ]; [ S setState: 24 ] ; [ S Detach: O ]; [ S release ]; [ O release ]; [ pool drain ]; return 0 ; } @end

// main.m #import "application.h" int main(void) { return [Application run]; }

GNUStep környezetben a következő GNUMakefile segítségével fordíthajuk le az alkalmazást :

include $(GNUSTEP_MAKEFILES)/common.make TOOL_NAME = Executable Executable_OBJC_FILES = application.m main.m subject.m observer.m concretesubject.m concreteobserver.m include $(GNUSTEP_MAKEFILES)/tool.make

Megjegyzés - Többszörös öröklődés hiánya

Azokban a nyelvekben amelyekben nincs lehetőség többszörös öröklődésre, ez a minta nehezen szabható hozzá már meglévő keretrendszerek elemeihez. Vegyük például az Objective-C-t és a Cocoa környezetet. Ha specializálni szeretnénk egy osztályt oly módon hogy mefigyelhető lehessen, szükséges lenne örökölni, az adott osztályból valamint a mintában szereplő Subject osztáylból is. A problémát megkerülhetjük például ha a Subject osztályt protokollként valósítjuk meg, ám ekkor minden ConcreteSubject megvalósításnál az egész megfigyelési funkcionalítást létre kell hoznunk.

Egy másik lehetőségként aggregálhatunk egy Subject példányt az eredeti osztályunk leszármazottjába. Objective-C-ben ezt metehetjük hiszen az absztrakt osztály példányosítható (más nyelvekben nyílván nem absztrakt osztályként kell megvalósítani a Subject osztályt). Ezután létre kell hoznunk a Subject-nek megfelelő interfészt az új osztályon (Attach, Detach). Ezek után az új osztály Attach és Detach eljárásai csak beburkolják az aggregált Subject megfelelő eljárásait. Az osztály a megfelelő helyeken meghívja az aggregált Subject Notify metódusát.

Egy, az előzőhöz kissé hasonló lehetséges megoldás ami nem egyezik tökéletesen a minta szerkezetével, hogy a Subject osztályba aggregálunk egy Observable példányt. Példa:

// Observable.h #include @interface Observable : NSObject { NSMutableArray* observers; } -(id) init; -(void) dealloc; -(void) attach: (id) object withSelector: (SEL) sel; -(void) detach: (id) object withSelector: (SEL) sel; -(void) notify; @end
//Observable.m #include "observable.h" @implementation Observable -(id) init{ observers = [[NSMutableArray alloc] init]; return self; } -(void) dealloc{ [observers release]; [super dealloc]; } -(void) attach: (id) object withSelector: (SEL) sel{ NSInvocation* handler = [NSInvocation invocationWithMethodSignature: [[object class] instanceMethodSignatureForSelector: sel]]; [handler setTarget: object]; [handler setSelector: sel]; [observers addObject: handler]; } -(void) detach: (id) object withSelector: (SEL) sel{ NSMutableArray* discard = [NSMutableArray array]; for(NSInvocation* invocation in observers){ if( [invocation.target isEqual: object] && sel_isEqual(invocation.selector, sel)){ [discard addObject: invocation]; } } [observers removeObjectsInArray: discard]; } -(void) notify{ for(NSInvocation* invocation in observers) { [invocation invoke]; } } @end
//main.m @interface Observer: NSObject { } -(void) print; @end @implementation Observer -(void) print{ NSLog(@"updated:)"); } @end @interface Subject: NSObject { Observable* sub; } @property (readonly) (Observable*) sub; -(void) update; @end @implementation Subject @synthesize sub; -(id) alloc{ sub = [Observable new]; return self; } -(void) dealloc{ [sub release]; [super dealloc]; } -(void) update{ [sub notify]; } @end int main(void) { NSAutoreleasePool * pool = [NSAutoreleasePool new]; Subject* subject = [[Subject alloc] init]; Observer* o = [[Observer alloc] init]; [subject.sub attach: o withSelector: @selector(print)]; [subject update]; [subject.sub detach: o withSelector: @selector(print)]; [subject update]; [pool release]; return 0; }

Állapot

Állapot tervezési minta

Rövid leírás

Lehetővé tenni, hogy egy objektum megváltoztassa a viselkedését, ha az állapota változik. A hatása olyan, mintha az objektum megváltoztatná az osztályát.

Felhasználhatóság

Résztvevők

Példa kód

A következő példa kód szemlélteti az Állapot tervminta egy lehetséges megvalósítását Objective-C nyelven. Esetünkben egy bankszámla működése kísérhető nyomon (3 állapot szerint):

main.h

#import "szamla.h" int main (void) { NSAutoreleasePool * pool = [ NSAutoreleasePool new ] ; id szamlaEgy = [ [ Szamla alloc ] initParameterrel: @"Vitay Georgina" ]; [ szamlaEgy kamatotJovair ] ; [ szamlaEgy befizet : 500.0 ] ; [ szamlaEgy befizet : 300.0 ] ; [ szamlaEgy kamatotJovair ] ; [ szamlaEgy befizet : 1000.0 ] ; [ szamlaEgy kamatotJovair ] ; [ szamlaEgy kivesz : 2000.0 ] ; [ szamlaEgy kivesz : 1500.0 ] ; [ szamlaEgy kamatotJovair ] ; [ pool drain ]; return 0 ; }

szamla.h

#import <Foundation/Foundation.h> //elodeklaracio @class State; //Context-nek feleltetheto meg @interface Szamla: NSObject { State* allapot; NSString* tulajdonos; } @property (readwrite, assign) State* allapot; @property (readwrite, assign) NSString* tulajdonos; - (id) initParameterrel : (NSString*) tulajdonosa ; - (double) getEgyenleg ; - (void) befizet: (double) osszeg; - (void) kivesz: (double) osszeg; - (void) kamatotJovair; - (void) kiir; @end ;

szamla.m

#import "szamla.h" #import "ezustUgyfel.h" @implementation Szamla @synthesize allapot=allapot; @synthesize tulajdonos=tulajdonos; - (id) initParameterrel : (NSString*) tulajdonosa { tulajdonos = tulajdonosa ; allapot = [ [ EzustUgyfel alloc ] inic : 0.0 sz: self]; NSLog (@"Szamla letrehozva."); [ self kiir ]; return self ; } - (double) getEgyenleg { return allapot.egyenleg ; } - (void) befizet: (double) osszeg { [ allapot befizet : osszeg ]; NSLog (@"Befizet: %f Ft-ot", osszeg); [ self kiir ]; } - (void) kivesz: (double) osszeg { [ allapot kivesz : osszeg ]; NSLog (@"Kivesz: %f Ft-ot", osszeg); [ self kiir ]; } - (void) kamatotJovair { [ allapot kamatotJovair ]; NSLog (@"Kamat jovairas"); [ self kiir ]; } - (void) kiir; { NSLog (@"Tulajdonos: %@", tulajdonos); NSLog (@"Egyenleg = %f", [ self getEgyenleg ]); [ allapot allapotKiir ]; NSLog (@""); } @end ;

state.h

#import <Foundation/Foundation.h> #import "szamla.h" #define ABSTRACT //Statenek feleltetheto meg ABSTRACT @interface State: NSObject { Szamla * szamla; double egyenleg; double _kamat; double _alsoLimit; double _felsoLimit; } @property (readwrite, assign) Szamla* szamla; @property (readwrite, assign) double egyenleg; // ezeket a muveleteket kell a state1,state2, ...., staten osztalyokban megvalositani - (void) befizet: (double) osszeg; - (void) kivesz: (double) osszeg; - (void) kamatotJovair; - (void) allapotKiir; @end ;

state.m

#import "state.h" @implementation State @synthesize szamla=szamla; @synthesize egyenleg=egyenleg; - (void) befizet: (double) osszeg { ABSTRACT } - (void) kivesz: (double) osszeg { ABSTRACT } - (void) kamatotJovair { ABSTRACT } - (void) allapotKiir { ABSTRACT } @end ;

negativUgyfel.h

#import <Foundation/Foundation.h> #import "state.h" #import "szamla.h" //State1nek feleltetheto meg @interface NegativUgyfel : State { } - (NegativUgyfel*) inicParameterrel : (State*) state; - (NegativUgyfel*) inic : (double) egyenleg sz: (Szamla*) szamlaa; - (void) initialize ; - (void) AllapotValtozasEllenorzese; - (void) befizet: (double) osszeg; - (void) kivesz: (double) osszeg; - (void) kamatotJovair; - (void) allapotKiir; @end ;

negativUgyfel.m

#import "state.h" #import "szamla.h" #import "negativUgyfel.h" #import "ezustUgyfel.h" @implementation NegativUgyfel - (NegativUgyfel*) inicParameterrel : (State*) state { return [ self inic : state.egyenleg sz: state.szamla ]; } - (NegativUgyfel*) inic : (double) egyenlege sz: (Szamla*) szamlaa { egyenleg = egyenlege; szamla = szamlaa; [ self initialize ]; return self; } - (void) initialize { _kamat = 0.0; _alsoLimit = -100.0; _felsoLimit = 0.0; } - (void) befizet: (double) osszeg { egyenleg += osszeg; [ self AllapotValtozasEllenorzese ]; } - (void) kivesz: (double) osszeg { NSLog (@"Nincs eleg penz a szamlan kifizeteshez!"); } - (void) kamatotJovair { } - (void) AllapotValtozasEllenorzese { if (egyenleg > _felsoLimit) { szamla.allapot = [[ EzustUgyfel alloc ] inicParameterrel : self ]; } } - (void) allapotKiir { NSLog (@"Allapot = negativUgyfel"); } @end ;

ezustUgyfel.h

#import <Foundation/Foundation.h> #import "state.h" #import "szamla.h" //State2nek feleltetheto meg @interface EzustUgyfel : State { } - (EzustUgyfel*) inicParameterrel : (State*) state; - (EzustUgyfel*) inic : (double) egyenleg sz: (Szamla*) szamlaa; - (void) initialize ; - (void) AllapotValtozasEllenorzese; - (void) befizet: (double) osszeg; - (void) kivesz: (double) osszeg; - (void) kamatotJovair; - (void) allapotKiir; @end ;

ezustUgyfel.m

#import "state.h" #import "szamla.h" #import "ezustUgyfel.h" #import "aranyUgyfel.h" #import "negativUgyfel.h" @implementation EzustUgyfel - (EzustUgyfel*) inicParameterrel : (State*) state { return [ self inic : state.egyenleg sz: state.szamla ]; } - (EzustUgyfel*) inic : (double) egyenlege sz: (Szamla*) szamlaa { egyenleg = egyenlege; szamla = szamlaa; [ self initialize ]; return self; } - (void) initialize { _kamat = 0.01; _alsoLimit = 0.0; _felsoLimit = 1000.0; } - (void) befizet: (double) osszeg { egyenleg += osszeg; [ self AllapotValtozasEllenorzese ]; } - (void) kivesz: (double) osszeg { egyenleg -= osszeg; [ self AllapotValtozasEllenorzese ]; } - (void) kamatotJovair { egyenleg += _kamat * egyenleg; [ self AllapotValtozasEllenorzese ]; } - (void) AllapotValtozasEllenorzese { if (egyenleg < _alsoLimit) { szamla.allapot = [[ NegativUgyfel alloc ] inicParameterrel : self]; } else if (egyenleg > _felsoLimit) { szamla.allapot = [[ AranyUgyfel alloc ] inicParameterrel : self]; } } - (void) allapotKiir { NSLog (@"Allapot = ezustUgyfel"); } @end ;

aranyUgyfel.h

#import <Foundation/Foundation.h> #import "state.h" #import "szamla.h" //State3nak feleltetheto meg @interface AranyUgyfel : State { } - (AranyUgyfel*) inicParameterrel : (State *)state; - (AranyUgyfel*) inic : (double) egyenlege sz: (Szamla*) szamlaa; - (void) initialize ; - (void) AllapotValtozasEllenorzese; - (void) befizet: (double) osszeg; - (void) kivesz: (double) osszeg; - (void) kamatotJovair; - (void) allapotKiir; @end ;

aranyUgyfel.m

#import "state.h" #import "szamla.h" #import "aranyUgyfel.h" #import "ezustUgyfel.h" #import "negativUgyfel.h" @implementation AranyUgyfel - (AranyUgyfel*) inicParameterrel : (State*) state { return [ self inic : state.egyenleg sz: state.szamla ]; } - (AranyUgyfel*) inic : (double) egyenlege sz: (Szamla*) szamlaa { egyenleg = egyenlege; szamla = szamlaa; [ self initialize ]; return self; } - (void) initialize { _kamat = 0.05; _alsoLimit = 1000.0; _felsoLimit = 10000000.0; } - (void) befizet: (double) osszeg { egyenleg += osszeg; [ self AllapotValtozasEllenorzese ]; } - (void) kivesz: (double) osszeg { egyenleg -= osszeg; [ self AllapotValtozasEllenorzese ]; } - (void) kamatotJovair { egyenleg += _kamat * egyenleg; [ self AllapotValtozasEllenorzese ]; } - (void) AllapotValtozasEllenorzese { if (egyenleg < 0.0) { szamla.allapot = [[ NegativUgyfel alloc ] inicParameterrel : self]; } else if (egyenleg < _alsoLimit) { szamla.allapot = [[ EzustUgyfel alloc ] inicParameterrel : self]; } } - (void) allapotKiir { NSLog (@"Allapot = aranyUgyfel"); } @end ;

GNUmakefile

include $(GNUSTEP_MAKEFILES)/common.make TOOL_NAME = Allapot Allapot_OBJC_FILES = szamla.m state.m main.m aranyUgyfel.m ezustUgyfel.m negativUgyfel.m include $(GNUSTEP_MAKEFILES)/tool.make

Gyár

Gyár tervezési minta

Rövid leírás

A gyár egy olyan objektum, ami más objektumokat hoz létre, így lehetőségünk van futásidőben eldönteni, hogy melyik alosztály objektumait szeretnénk felhasználni egy-egy művelethez. Bizonyos esetekben a gyártott objektumok osztálya nem különbözik. Ha a gyárnak több gyártás művelete is van, lehetőségünk van összetartozó objektumokat definiálni.

Felhasználhatóság

Résztvevők

Példa kód

A következő példa kód szemlélteti a Gyár két lehetséges felhasználását Objective-C nyelven. A program majd egy egyszerű mesét mesél el a jó és a gonosz összecsapásáról.

Az IChar.h fájlban definiáljuk a mesében résztvevő szereplők interfészét. Ez felel meg az AbstractProduct osztálynak a tervmintából.

IChar.h

#import <Foundation/Foundation.h> @protocol IChar - (NSString *) getName; - (void) setName: (NSString*) name; - (void) turn; - (int) getPlace; - (id<IChar>) initWithName: (NSString*) name; - (void) setOpponent: (id<IChar>) opp; - (void) hurt; - (NSString *) getAttr; @end

Az IFactory.h fájlban definiáljuk a gyáraink interfészét. Ez felel meg az AbstractFactory osztálynak. Az IStringFactory csak NSString*-ot hoz létre: neveket és tulajdonságokat. Az ITaleFactory létrehozza a mese két szereplőjét és megadja a mese címét.

IFactory.h

#import <Foundation/Foundation.h> #import "IChar.h" @protocol IStringFactory - (NSString *) create; @end @protocol ITaleFactory - (id <IChar>) createFirst; - (id <IChar>) createSecond; - (NSString *) createTitle; @end

A World statikus osztály képviseli a világot: a helyszineit, valamint a mese leírásáért felelős.

World.h

#import <Foundation/Foundation.h> #import "IChar.h" #import "IFactory.h" @interface World : NSObject { } + (int) getMaxPlace; + (NSString *) getPlace: (int) pnum; + (NSString *) getPlaceAt: (int) pnum; + (NSString *) getPlaceTo: (int) pnum; + (void) printTale: (id<ITaleFactory>) factory; + (void) printStatement: (NSString *) statement; + (void) endOfTale; @end

World.m

#import "World.h" #include <stdio.h> static int tellatale; @implementation World + (int) getMaxPlace { return 4; } + (NSString *) getPlace: (int) pnum { switch (pnum) { case 0: return @"dombok"; case 1: return @"volgyek"; case 2: return @"erdok"; case 3: return @"mezok"; default: return @"ismeretlen"; } } + (NSString *) getPlaceAt: (int) pnum { switch (pnum) { case 0: return @"dombokat"; case 1: return @"volgyeket"; case 2: return @"erdoket"; case 3: return @"mezoket"; default: return @"ismeretlent"; } } + (NSString *) getPlaceTo: (int) pnum { switch (pnum) { case 0: return @"dombokhoz"; case 1: return @"volgyekhez"; case 2: return @"erdokhoz"; case 3: return @"mezokhoz"; default: return @"ismeretlenbe"; } } + (void) endOfTale { tellatale = 0; } + (void) printStatement: (NSString *) statement { printf("%s\n", [statement UTF8String]); } + (void) printTale: (id) factory { tellatale = 1; id player1 = [factory createFirst]; id player2 = [factory createSecond]; NSString* title = [factory createTitle]; [World printStatement: title]; [player1 setOpponent: player2]; [player2 setOpponent: player1]; while (tellatale) { [player1 turn]; if (tellatale) [player2 turn]; } } @end

A GoodAttr és a BadAttr osztályok a jó és rossz tulajdonságok gyárjai, míg a NameGen1 osztály a nevek létrehozásáért felel.

GoodAttr.h

#import <Foundation/Foundation.h> #import "IFactory.h" @interface GoodAttr : NSObject { } @end

GoodAttr.m

#import "GoodAttr.h" #include <stdlib.h> @implementation GoodAttr - (NSString*) create { char* tul[3] = {"hosies", "rendithetetlen", "legendas"}; int k = rand()%3; return [[NSString alloc] initWithUTF8String: tul[k]]; } @end

BadAttr.h

#import <Foundation/Foundation.h> #import "IFactory.h" @interface BadAttr : NSObject <IStringFactory> { } @end

BadAttr.m

#import "BadAttr.h" #include <stdlib.h> @implementation BadAttr - (NSString*) create { char* tul[4] = {"satani", "gonosz", "ordogi", "pusztito"}; int k = rand()%4; return [[NSString alloc] initWithUTF8String: tul[k]]; } @end

NameGen1.h

#import <Foundation/Foundation.h> #import "IFactory.h" @interface NameGen1 : NSObject { } @end

NameGen1.m

#import "NameGen1.h" #include <stdio.h> #include <stdlib.h> @implementation NameGen1 - (NSString*) create { const char* npart[NLENGTH] = { "ana", "bot", "reg", "men", "esi", "tul", "sev", "ket" }; char name[NLENGTH]; int i; for (i = 0; i<NLENGTH; ++i) name[i] = 0; sprintf(name,"%s%s",npart[rand()%NLENGTH],npart[rand()%NLENGTH]); name[0]-=32; return [[NSString alloc] initWithUTF8String: name]; } @end

A GoodGuy és a BadGuy osztály valósítja meg a történetünk két szereplőjét.

GoodGuy.h

#import "IChar.h" #import "IFactory.h" @interface GoodGuy : NSObject <IChar> { NSString *myname; id<IStringFactory> tul; int place; id<IChar> opponent; int amIHurt; } @end

GoodGuy.m

#import "GoodGuy.h" #import "GoodAttr.h" #import "World.h" #include <stdlib.h> @implementation GoodGuy - (NSString *) getName { return myname; } - (void) setName: (NSString*) name { myname = name; } - (void) turn { int moverandom = rand() % 2; if ([opponent getPlace] == place) { moverandom = -1; } if (amIHurt) { if (rand()%2) { moverandom = 1; } if (moverandom == 1) { [World printStatement: [NSString stringWithFormat: @"A %@ %@ felpattant, es menekulni kezdett.", [self getAttr], myname]]; } else { [World printStatement: [NSString stringWithFormat: @"A %@ %@ gyorsan felallt, hogy ujra kuzdjon.", [self getAttr], myname]]; } amIHurt = 0; } switch (moverandom) { case -1: switch (rand()%3) { case 0: [World printStatement: [NSString stringWithFormat: @"A %@ %@ nagy lendulettel rontott neki ellenfelenek.", [self getAttr], myname]]; break; case 1: [World printStatement: [NSString stringWithFormat: @"A %@ %@ %@ sebesseggel ugrott ellenfelenek, es teritette le.", [self getAttr], myname, [self getAttr]]]; break; default: [World printStatement: [NSString stringWithFormat: @"A %@ %@ hatalmas pofont kevert le ellenfelenek.", [self getAttr], myname]]; break; } [opponent hurt]; break; case 0: moverandom = rand() % ([World getMaxPlace]-1); if (moverandom >= place) ++moverandom; if (moverandom == [opponent getPlace]) { switch (rand()%3) { case 0: [World printStatement: [NSString stringWithFormat: @"%@ eppen %@ ellenfelet kereste a %@ kozott, amikor hirtelen meglatta.", myname, [opponent getAttr], [World getPlace: moverandom]]]; break; case 1: [World printStatement: [NSString stringWithFormat: @"%@ a %@ fele nezett, es meglatta ellenfelet.", myname, [World getPlace: moverandom]]]; break; default: [World printStatement: [NSString stringWithFormat: @"%@ %@ tekintettel furkeszte a %@, es meglatta ellenfelet.", myname, [self getAttr], [World getPlaceAt: moverandom]]]; break; } } else { switch (rand()%3) { case 0: [World printStatement: [NSString stringWithFormat: @"%@ %@ ellenfelet kereste a %@ kozott, de teljesen eredmenytelenul.", myname, [opponent getAttr], [World getPlace: moverandom]]]; break; case 1: [World printStatement: [NSString stringWithFormat: @"%@ a %@ fele nezett, de nem volt ott senki.", myname, [World getPlace: moverandom]]]; break; default: [World printStatement: [NSString stringWithFormat: @"%@ %@ tekintettel furkeszte a %@, de nem latott ott senkit.", myname, [self getAttr], [World getPlaceAt: moverandom]]]; break; } } break; case 1: moverandom = rand() % ([World getMaxPlace]-1); if (moverandom >= place) ++moverandom; place = moverandom; switch (rand()%3) { case 0: [World printStatement: [NSString stringWithFormat: @"A %@ %@ atment a %@.", [self getAttr], myname, [World getPlaceTo: moverandom]]]; break; case 1: [World printStatement: [NSString stringWithFormat: @"A %@ %@ a %@ ment hogy tovabb keresse ellenfelet.", [self getAttr], myname, [World getPlaceTo: moverandom]]]; break; default: [World printStatement: [NSString stringWithFormat: @"A %@ %@ atrohant a %@.", [self getAttr], myname, [World getPlaceTo: moverandom]]]; break; } break; default: break; } } - (int) getPlace { return place; } - (id<IChar>) initWithName: (NSString*) name { myname = name; tul = [GoodAttr alloc]; place = rand()%[World getMaxPlace]; amIHurt = 0; return self; } - (void) setOpponent: (id<IChar>) opp { opponent = opp; } - (void) hurt { amIHurt = 1; } - (NSString *) getAttr { return [tul create]; } @end

BadGuy.h

#import "IChar.h" #import "IFactory.h" @interface BadGuy : NSObject <IChar> { NSString *myname; id<IStringFactory> tul; int place; int hp; id<IChar> opponent; int amIHurt; } @end

BadGuy.m

#import "BadGuy.h" #import "BadAttr.h" #import "World.h" #include @implementation BadGuy - (NSString *) getName { return myname; } - (void) setName: (NSString*) name { myname = name; } - (void) turn { int moverandom = rand() % 2; if ([opponent getPlace] == place) { moverandom = -1; } if (amIHurt) { --hp; if (hp>0) { [World printStatement: [NSString stringWithFormat: @"A %@ %@ gyorsan felallt, hogy ujra kuzdjon.", [self getAttr], myname]]; if (rand()%2) { moverandom = 1; } } else { [World printStatement: [NSString stringWithFormat: @"A %@ %@ megprobalt felallni, de %@ tagjaiban mar nem maradt ero. %@ legyozte ot!", [self getAttr], myname, [self getAttr], [opponent getName]]]; [World endOfTale]; return; } amIHurt = 0; } switch (moverandom) { case -1: [World printStatement: [NSString stringWithFormat: @"A %@ %@ hatalmas pofont kevert le ellenfelenek.", [self getAttr], myname]]; [opponent hurt]; break; case 0: moverandom = rand() % ([World getMaxPlace]-1); if (moverandom >= place) ++moverandom; if (moverandom == [opponent getPlace]) { [World printStatement: [NSString stringWithFormat: @"%@ %@ tekintettel furkeszte a %@, es meglatta ellenfelet.", myname, [self getAttr], [World getPlaceAt: moverandom]]]; } else { [World printStatement: [NSString stringWithFormat: @"%@ %@ tekintettel furkeszte a %@, de nem volt ott senki.", myname, [self getAttr], [World getPlaceAt: moverandom]]]; } break; case 1: moverandom = rand() % ([World getMaxPlace]-1); if (moverandom >= place) ++moverandom; place = moverandom; [World printStatement: [NSString stringWithFormat: @"A %@ %@ atrohant a %@.", [self getAttr], myname, [World getPlaceTo: moverandom]]]; break; default: break; } } - (int) getPlace { return place; } - (id) initWithName: (NSString*) name { myname = name; tul = [BadAttr alloc]; place = rand()%[World getMaxPlace]; amIHurt = 0; hp = 5; return self; } - (void) setOpponent: (id) opp { opponent = opp; } - (void) hurt { amIHurt = 1; } - (NSString *) getAttr { return [tul create]; } @end

Végül, de nem utolsó sorban a GoodNBadTaleFactory osztály felel a szereplők létrehozásáért és a címért. Inicializáláskor paraméterként igényel egy névgenerátort, ami alapján elnevezi a szereplőket.

GoodNBadTaleFactory.h

#import #import "IFactory.h" #import "GoodGuy.h" #import "BadGuy.h" #import "NameGen1.h" #import "IChar.h" @interface GoodNBadTaleFactory : NSObject { id player1; id player2; id names; } - (GoodNBadTaleFactory*) initWithNameGen: (id) ngen; @end

GoodNBadTaleFactory.m

#import "GoodNBadTaleFactory.h" #include <stdlib.h> @implementation GoodNBadTaleFactory - (id <IChar>) createFirst { player1 = [[GoodGuy alloc] initWithName: [names create]]; return player1; } - (id <IChar>) createSecond { player2 = [[BadGuy alloc] initWithName: [names create]]; return player2; } - (NSString *) createTitle { return [NSString stringWithFormat:@"Mese %@ %@ es %@ %@ osszecsapasarol\n", [player1 getAttr], [player1 getName], [player2 getAttr], [player2 getName]]; } - (GoodNBadTaleFactory*) initWithNameGen: (id<IStringFactory>) ngen { names = ngen; return self; } @end

A programot Windows 7 alatt GNUSteppel a ...\home\<User>\mese könyvtárba helyezve az alábbi batch fájllal fordítható:

compile.bat

gcc -o mese mese/mese.m mese/GoodNBadTaleFactory.m mese/BadAttr.m mese/GoodAttr.m mese/NameGen1.m mese/NameGen2.m mese/World.m mese/GoodGuy.m mese/BadGuy.m -I /GNUstep/System/Library/Headers -L /GNUstep/System/Library/Libraries -lobjc -lgnustep-base -fconstant-string-class=NSConstantString
;

Egyke

Egyke tervezési minta

Rövid leírás

Biztosítani, hogy egy osztályhoz csak egy példány tartozhat, és megteremteni a példány globális elérhetőségét.

Felhasználhatóság

Résztvevők

Példa kód

A következő példa kód szemlélteti az Egyke tervminta egy lehetséges megvalósítását Objective-C nyelven. Esetünkben egy NSStringet tartalmazó osztályról van szó, ahol ezen adattag tartalma kiírható, illetve megváltoztatható.

main.h

#import #import "egyke.h" int main (void) { NSAutoreleasePool * pool = [ NSAutoreleasePool new ] ; id vki = [Egyke instance]; [ vki kiir]; [[Egyke instance] setSzoveg : @"Masodik egyke szoveg" ]; [ vki kiir]; [ pool drain ]; return 0 ; }

egyke.h

#import @interface Egyke : NSObject { NSString* szoveg; } +(Egyke*)instance; -(void)kiir; -(void)setSzoveg: (NSString*) ujSzovegTartalom; @end

egyke.m

#import "egyke.h" @implementation Egyke static Egyke* _instance = nil; +(Egyke*)instance { @synchronized(self) { if (!_instance) [[self alloc] init]; return _instance; } return nil; } +(id)alloc { @synchronized(self) { NSAssert(_instance == nil, @"Megprobaltad a masodik egyket letrehozni!!!"); _instance = [super alloc]; return _instance; } return nil; } -(id)init { self = [super init]; if (self != nil) { szoveg = @"alapertelmezett egyke szoveg tartalom"; } return self; } -(void)kiir { NSLog(@"Az egyke szoveg tartalma: %@", szoveg); } -(void)setSzoveg : (NSString*) ujSzovegTartalom { szoveg = ujSzovegTartalom; return; } @end

GNUmakefile

include $(GNUSTEP_MAKEFILES)/common.make TOOL_NAME = Egyke Egyke_OBJC_FILES = egyke.m main.m include $(GNUSTEP_MAKEFILES)/tool.make

Prototípus

Prototípus tervezési minta

Rövid leírás

Elemek létrehozása előzetes minta (prototípus) alapján.

Felhasználhatóság

A prototípus mintát használjuk, ha a rendszernek függetlennek kell lennie, hogy a terméket miként hozzuk létre, állítjuk össze és reprezentáljuk.

Résztvevők

Példa kód

A következő példa kód szemlélteti a Prototípus tervminta egy lehetséges megvalósítását Objective-C nyelven.

Prototype.h

@protocol Prototype -(id) Clone; @end

ConcPrototype.h

#include "Prototype.h" #include @interface ConcPrototype : NSObject { NSString* str; } -(id) Clone; -(NSString*) getStr; @end

ConcPrototype.m

#include "ConcPrototype.h" #include @implementation ConcPrototype -(id) init{ str = [NSString new]; return self; } -(id) initWithString: (NSString*) pStr{ str = pStr; return self; } -(NSString*) getStr{ return str; } -(id) Clone { return [[ConcPrototype alloc] initWithString: str]; } @end

PrototypeMain.m

#include "ConcPrototype.h" #include @interface Client : NSObject { ConcPrototype* cprot; id prot; } -(id) init; -(void) test; @end @implementation Client -(id) init{ cprot = [[ConcPrototype alloc] initWithString: @"Teszt"]; prot = nil; return self; } -(void) test{ prot = [cprot Clone]; NSLog([prot getStr]); } @end int main(){ NSAutoreleasePool * pool = [NSAutoreleasePool new]; NSLog(@"start"); [[[Client alloc] init] test]; [pool release] }

Könnyűsúlyú

Könnyűsúlyú tervezési minta

Rövid leírás

Megosztás használata nagy számú finomszemcsés(sok adatot tartalmazó) objektum hatékony kezeléséhez.

Felhasználhatóság

Résztvevők

Példa kód

A következő példa kód szemlélteti a Könnyűsúlyú tervminta egy lehetséges megvalósítását Objective-C nyelven.

FlyweightChar.h

#ifndef FlyweightChar_INCLUDED #define FlyweightChar_INCLUDED @protocol FlyweightChar -(char) getChar; @end #endif

ConcFlyweightCharDigit.h

#ifndef ConcFlyweightCharDigit_INCLUDED #define ConcFlyweightCharDigit_INCLUDED #include "FlyweightChar.h" #include @interface ConcFlyweightCharDigit: NSObject { char c; } -(id) initWithChar: (char) ch; -(char) getChar; @end #endif

ConcFlyweightCharDigit.m

#include "ConcFlyweightCharDigit.h" #include @implementation ConcFlyweightCharDigit -(id) initWithChar: (char) ch{ c= ch; return self; } -(char) getChar{ return c; } @end

ConcFlyweightCharNonDigit.h

#ifndef ConcFlyweightCharNonDigit_INCLUDED #define ConcFlyweightCharNonDigit_INCLUDED #include "FlyweightChar.h" #include @interface ConcFlyweightCharNonDigit: NSObject { char c; } -(id) initWithChar: (char) ch; -(char) getChar; @end #endif

ConcFlyweightCharNonDigit.m

#include "ConcFlyweightCharNonDigit.h" @implementation ConcFlyweightCharNonDigit -(id) initWithChar: (char) ch{ c= ch; return self; } -(char) getChar{ return c; } @end

ConcFlyweightCharFactory.h

#ifndef FlyweightCharFactory_INCLUDED #define FlyweightCharFactory_INCLUDED #include "FlyweightChar.h" #include "ConcFlyweightCharDigit.h" #include "ConcFlyweightCharNonDigit.h" #include @interface FlyweightCharFactory: NSObject { ConcFlyweightCharDigit* digits[10]; } -(id) getFlyweightChar: (char) ch; @end #endif

ConcFlyweightCharFactory.m

#include "FlyweightCharFactory.h" #include @implementation FlyweightCharFactory -(id) getFlyweightChar: (char) ch{ if(isdigit(ch)) { int i = ch - '0'; if(digits[i] == nil) digits[i] = [[ConcFlyweightCharDigit alloc] initWithChar: ch]; return digits[i]; } else return [[ConcFlyweightCharNonDigit alloc] initWithChar: ch]; } @end

ConcFlyweightCharMain.m

#include "FlyweightCharFactory.h" #include int main(){ NSAutoreleasePool * pool = [NSAutoreleasePool new]; FlyweightCharFactory* fac = [FlyweightCharFactory new]; NSLog([NSString stringWithFormat: @"%c", [[fac getFlyweightChar: '9'] getChar]]); [pool release] return 0; }

Stratégia

Stratégia tervezési minta

Rövid leírás

A minta lehetőséget ad algoritmusok halmazának létrehozására, azok beágyazására és kicserélhetőségük biztosítására.

Felhasználhatóság

Résztvevők

Példa kód

A következő példa kód szemlélteti a Könnyűsúlyú tervminta egy lehetséges megvalósítását Objective-C nyelven.

PrintStrategy.h

#ifndef PrintStrategy_INCLUDED #define PrintStrategy_INCLUDED @protocol PrintStrategy -(void) print; @end #endif

ConcPrintStrategy1.h

#include "PrintStrategy.h" #include @interface ConcPrintStrategy1 : NSObject { NSString* text; } -(id) initWithString: (NSString*) str; -(void) print; @end

ConcPrintStrategy1.m

#include "ConcPrintStrategy1.h" #include @implementation ConcPrintStrategy1 -(id) initWithString: (NSString*) str{ text = str; return self; } -(void) print{ NSLog(text); } @end

ConcPrintStrategy2.h

#include "PrintStrategy.h" #include @interface ConcPrintStrategy2 : NSObject { NSString* text; } -(id) initWithString: (NSString*) str; -(void) print; @end

ConcPrintStrategy2.m

#include "ConcPrintStrategy2.h" #include @implementation ConcPrintStrategy2 -(id) initWithString: (NSString*) str{ text = str; return self; } -(void) print{ NSLog(@"Hurra! ::: "); NSLog(text); NSLog(@" ::: !arruH"); } @end

StrategyContext.h

#include "PrintStrategy.h" #include @interface StrategyContext : NSObject{ id printer; } -(void) setStrategy: (id) strat; -(void) print; @end

StrategyContext.m

#include "StrategyContext.h" #include @implementation StrategyContext -(void) setStrategy: (id) strat{ printer = strat; } -(void) print{ [printer print]; } @end

StrategyMain.m

#include "ConcPrintStrategy1.h" #include "ConcPrintStrategy2.h" #include "StrategyContext.h" #include int main(){ StrategyContext* cont = [StrategyContext new]; [cont setStrategy: [[ConcPrintStrategy1 alloc] initWithString: @"Teszt1"]]; [cont print]; [cont setStrategy: [[ConcPrintStrategy2 alloc] initWithString: @"Teszt2"]]; [cont print]; return 0; }