Observer
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
-
Ha egy absztrakcióban két olyan tényező szerepel, amelyek közül
az egyik függ a másiktól. Ha ezeket külön objektumoknak tekintjük,
akkor lehetséges egymástól független változtatásuk és újrafelhasználásuk.
-
Amikor egy objektum állapotának megváltozása más objektumok
változtatását teszi szükségessé, és nem ismert az objektumok száma.
-
Amikor egy objektumnak üzenetet kell küldenie más objektumoknak,
amelyekről nem tehetünk fel semmit; azaz nem akarjuk szorosan összekapcsolni
ezeket az objektumokat.
Résztvevők
-
Subject (Tárgy)
Ismeri a figyelőit amelyek száma tetszőleges.
Lehetőséget biztosít figyelő onjektumok hozzávételére illetve eltávolítására.
-
ConcreteSubject (Konkrét Tárgy)
Tartalmazza a konkrét figyelők számára érdekes állapotot. Állapotváltozás esetén értesíti figyelőit.
-
Observer (Figyelő)
Meghatározza a módosítási felületét azoknak az objektumoknak, amelyeket értesíteni kell.
-
ConcreteObserver (Konkrét Figyelő)
Hivatkozik konkrét tárgy objektumra. Tartaémazza az állapotot, amelynek konzisztensnek kell lennie
a tárgyéval. Implementálja a figyelő módosítási felületét, ezzel biztosítva a konzisztenciát.
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
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
-
Egy objektum viselkedését az állapota határozza meg, és a viselkedést futási
időben kell megváltoztatni az állapot függvényében.
-
A műveletekben nagy méretű, több részes feltételes utasítások szerepelnek, ahol
a feltétel az objektum állapotától függ. Az állapotot rendszerint egy felsorolási
típussal adjuk meg. Gyakran több művelet is ugyanezt a feltételes szerkezetet
tartalmazza.
Résztvevők
-
Context
Az ügyfeleknek (kliens objektumok) megadja a felületet. Az aktuális
állapot meghatározásával együtt karbantartja a state változót úgy, hogy az
egy megfelelő Statei osztály példánya legyen.
-
State
Meghatározza a speiális állapotok közös felületét.
-
Statei
Minden osztály a Context egy állapotához tartozó speiális viselkedést implementál.
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):
-
egyenleg <= 0: negativUgyfel, amely állapot szerint már nem lehet készpénzt felvenni, és kamatot sem írnak jóvá.
-
0 < egyenleg <= 1000: ezustUgyfel, amely állapot szerint lehet készpénzt felvenni, kivenni, kamatot (0.01) jóváírni.
-
1000 < egyenleg: aranyUgyfel, amely állapot szerint szintén lehet készpénzt felvenni, kivenni, kamatot (0.05) jóváírni.
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
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
-
Egy vagy több objektum létrehozása úgy, hogy nem tudjuk előre, pontosan mi lesz az alosztálya,
de a lehetőségeket ismerjük.
-
Különböző tulajdonságú azonos típusú objektumok létrehozása különböző gyárakkal.
Résztvevők
-
Context
Az eredményt felhasználó objektum.
-
AbstractFactory
Meghatározza, hogy a konkrét gyárnak milyen gyártási metódusai lesznek.
-
AbstractProduct
A létrehozandó objektum ősosztálya. Ennek az interfészén keresztül tudjuk majd később ezelni
a konkrét létrehozott objektumot.
-
Factory
A konkrét gyár, ami elkészíti a CreateProduct függvényével a konkrét objektumot.
-
Product
A konkrét objektum, aminek a típusát a gyár beállítása segítségével futásidőben választhatjuk meg.
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
;
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.
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ó.
#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
include $(GNUSTEP_MAKEFILES)/common.make
TOOL_NAME = Egyke
Egyke_OBJC_FILES = egyke.m main.m
include $(GNUSTEP_MAKEFILES)/tool.make
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.
A következő példa kód szemlélteti a Prototípus tervminta egy lehetséges megvalósítását Objective-C nyelven.
Megosztás használata nagy számú finomszemcsés(sok adatot tartalmazó) objektum hatékony kezeléséhez.
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.
#ifndef FlyweightChar_INCLUDED
#define FlyweightChar_INCLUDED
@protocol FlyweightChar
-(char) getChar;
@end
#endif
#ifndef ConcFlyweightCharDigit_INCLUDED
#define ConcFlyweightCharDigit_INCLUDED
#include "FlyweightChar.h"
#include
@interface ConcFlyweightCharDigit: NSObject {
char c;
}
-(id) initWithChar: (char) ch;
-(char) getChar;
@end
#endif
#ifndef ConcFlyweightCharNonDigit_INCLUDED
#define ConcFlyweightCharNonDigit_INCLUDED
#include "FlyweightChar.h"
#include
@interface ConcFlyweightCharNonDigit: NSObject {
char c;
}
-(id) initWithChar: (char) ch;
-(char) getChar;
@end
#endif
#include "ConcFlyweightCharNonDigit.h"
@implementation ConcFlyweightCharNonDigit
-(id) initWithChar: (char) ch{
c= ch;
return self;
}
-(char) getChar{
return c;
}
@end
#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
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.
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.
#ifndef PrintStrategy_INCLUDED
#define PrintStrategy_INCLUDED
@protocol PrintStrategy
-(void) print;
@end
#endif
#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;
}