2010-02-10 14 views
12

Necesito desarrollar un patrón de estrategia donde tengo una clase principal con otras tres clases donde necesito referirme a los objetos de las otras tres clases usando el objeto de clase principal. Para resolver esto, ¿me ayudará el patrón de estrategia? Si es así, ¿me das la sintaxis en Objective-C?¿Cómo crear un patrón de estrategia en Objective-C?

+0

Esto parece ser un duplicado de su pregunta existente: http://stackoverflow.com/questions/2229026 –

+0

Sí, pero no he mencionado nada acerca patrón de estrategia en mi pregunta anterior – Cathy

Respuesta

39

Tendrá que mirar el mecanismo protocol de Objective-C. Aquí hay un protocolo simple con un solo método requerido:

@protocol Strategy <NSObject> 

@required 
- (void) execute; 

@end 

A continuación, se declara una clase que cumple con ese protocolo:

@interface ConcreteStrategyA : NSObject <Strategy> 
{ 
    // ivars for A 
} 
@end 

La aplicación debe proporcionar el método -execute (desde que fue declarada como @required):

@implementation ConcreteStrategyA 

- (void) execute 
{ 
    NSLog(@"Called ConcreteStrategyA execute method"); 
} 

@end 

Usted puede hacer una clase similar ConcreteStrategyB, pero no voy a mostrar aquí.

Finalmente, haga una clase de contexto con una propiedad que mantenga la estrategia actual.

@interface Context : NSObject 
{ 
    id<Strategy> strategy; 
} 
@property (assign) id<Strategy> strategy; 

- (void) execute; 

@end 

Aquí está la implementación. El método que delega en el método -execute de la estrategia simplemente se llama también -execute, pero no tiene que ser así.

@implementation Context 

@synthesize strategy; 

- (void) execute 
{ 
    [strategy execute]; 
} 

@end 

Ahora voy a hacer unos pocos casos y ponerlos en uso:

salida
ConcreteStrategyA * concreteStrategyA = [[[ConcreteStrategyA alloc] init] autorelease]; 
ConcreteStrategyB * concreteStrategyB = [[[ConcreteStrategyB alloc] init] autorelease]; 
Context * context = [[[Context alloc] init] autorelease]; 

[context setStrategy:concreteStrategyA]; 
[context execute]; 
[context setStrategy:concreteStrategyB]; 
[context execute];  

La consola muestra que la estrategia se cambió correctamente:

2010-02-09 19:32:56.582 Strategy[375:a0f] Called ConcreteStrategyA execute method 
2010-02-09 19:32:56.584 Strategy[375:a0f] Called ConcreteStrategyB execute method 

Tenga en cuenta que si el El protocolo no especifica @required, el método es opcional. En este caso, el contexto tiene que comprobar si la estrategia implementa el método:

- (void) execute 
{ 
    if ([strategy respondsToSelector:@selector(execute)]) 
     [strategy execute]; 
} 

Este es un patrón común que se llama cacao delegation. Para obtener más información sobre la delegación y otros patrones de diseño en Cocoa, see this.

+0

Gracias u tanto para el respuesta, una duda, ¿qué es la palabra clave 'setStrategy' aquí representa en las instancias que ha realizado. – Cathy

+0

El método '-setStrategy:' se genera automáticamente con la directiva '@ sintetizar'. Si la propiedad se declara 'retener', se encarga de retener/liberar (pero aún tiene que liberarlo en' -dealloc'). Pero si la propiedad se declara 'assign', realiza una asignación simple como una referencia débil, con la suposición de que la instancia asignada se garantiza que existe y se administrará en otro lugar. En ese caso, no debería ser lanzado. ... De hecho, voy a cambiar mi respuesta a esta segunda forma. –

+0

Gracias por la respuesta.El @protocol debería necesitar declararlo en el archivo separado – Cathy

1

Aquí hay un poco más de un ejemplo concreto. Puede poner cada elemento en un archivo separado. Lo puse todo en un solo archivo para facilitar la comprensión.

// main.m 
// StrategyWikipediaExample 
// 
// Created by steve on 2014-07-08. 
// Copyright (c) 2014 steve. All rights reserved. 
// 

#import <Foundation/Foundation.h> 

/** 
Equivalent to Java Interface 
All concrete Strategies conform to this protocol 
*/ 
@protocol MathOperationsStrategy<NSObject> 
- (void)performAlgorithmWithFirstNumber:(NSInteger)first secondNumber:(NSInteger)second; 
@end 

/** 
Concrete Strategies. 
Java would say they "Extend" the interface. 
*/ 

@interface AddStrategy : NSObject<MathOperationsStrategy> 
@end 
@implementation AddStrategy 
- (void)performAlgorithmWithFirstNumber:(NSInteger)first secondNumber:(NSInteger)second 
{ 
    NSInteger result = first + second; 
    NSLog(@"Adding firstNumber: %ld with secondNumber: %ld yields : %ld", first, second, result); 
} 
@end 

@interface SubtractStrategy : NSObject<MathOperationsStrategy> 
@end 
@implementation SubtractStrategy 
- (void)performAlgorithmWithFirstNumber:(NSInteger)first secondNumber:(NSInteger)second 
{ 
    NSInteger result = first - second; 
    NSLog(@"Subtracting firstNumer: %ld with secondNumber: %ld yields: %ld", first, second, result); 
} 
@end 

@interface MultiplyStrategy : NSObject<MathOperationsStrategy> 
@end 
@implementation MultiplyStrategy 
- (void)performAlgorithmWithFirstNumber:(NSInteger)first secondNumber:(NSInteger)second 
{ 
    NSInteger result = first * second; 
    NSLog(@"Multiplying firstNumber: %ld with secondNumber: %ld yields: %ld", first, second, result); 
} 
@end 

@interface Context : NSObject 
@property (weak, nonatomic)id<MathOperationsStrategy>strategy; // reference to concrete strategy via protocol 
- (id)initWithMathOperationStrategy:(id<MathOperationsStrategy>)strategy; // setter 
- (void)executeWithFirstNumber:(NSInteger)first secondNumber:(NSInteger)second; 
@end 
@implementation Context 
- (id)initWithMathOperationStrategy:(id<MathOperationsStrategy>)strategy 
{ 
    if (self = [super init]) { 
     _strategy = strategy; 
    } 
    return self; 
} 
- (void)executeWithFirstNumber:(NSInteger)first secondNumber:(NSInteger)second 
{ 
    [self.strategy performAlgorithmWithFirstNumber:first secondNumber:second]; 
} 
@end 


int main(int argc, const char * argv[]) 
{ 

    @autoreleasepool { 
     id<MathOperationsStrategy>addStrategy = [AddStrategy new]; 
     Context *contextWithAdd = [[Context alloc] initWithMathOperationStrategy:addStrategy]; 
     [contextWithAdd executeWithFirstNumber:10 secondNumber:10]; 

    } 
    return 0; 
} 
Cuestiones relacionadas