Objective-C中的策略模式

时间:2018-08-29 15:09:07

标签: ios objective-c strategy-pattern

我写了一个示例代码策略设计模式。

@protocol MyProtocol
- (void)execute1;
@end


@interface BaseClass : NSObject
@property(nonatomic, assign) NSInteger commonValue;
- (void)commonCalculator;
@end


@interface DogClass : BaseClass <MyProtocol>
@end

@interface CatClass : BaseClass <MyProtocol>
@end

此外,我想创建一个BaseClass来实现通用逻辑。
但是,无法从MyProtocol类型访问BaseClass。

例如

- (void)foo {
    NSInteger type = 0;

    id<MyProtocol> obj = [self simpleFactory:type];
    [obj execute1]; // It works!!

    // I'd like the following code. However compile error occurs.
    [obj commonCalculator]; // error
    obj.commonValue = 10; // error

    // I don't want the following code.
    if (type == 0 ) {
        [(DogClass *)obj commonCalculator];
        ((DogClass *)obj).commonValue = 10;
    } else {
        [(CatClass *)obj commonCalculator];
        ((CatClass *)obj).commonValue = 10;
    }
}

- (id<MyProtocol>)simpleFactory:(NSInteger)type {
    if (type == 0) {
        return [[DogClass alloc] init];
    } else {
        return [[CatClass alloc] init];
    }
}

在使用策略模式时是否可以在BaseClass中使用通用代码?

2 个答案:

答案 0 :(得分:1)

如果BaseClass实现了<MyProtocol>的默认行为,那么BaseClass应该采用并实现<MyProtocol>

@interface BaseClass : NSObject <MyProtocol>
@property(nonatomic, assign) NSInteger commonValue;
- (void)commonCalculator;
@end

然后,子类将继承该协议:

@interface DogClass : BaseClass
...
@interface CatClass : BaseClass
...

好消息是,子类可以调用[super execute1],并且如果您尝试使用BaseClass的实例或将id<MyProtocol>的实例用作BaseClass <MyProtocol>,编译器将不会抱怨。

现在,如果出于某些无法解释的原因,您必须将BaseClass的超类实现的代码分离到其自己的模块中,则可以通过创建采用{在此处实现您的默认实现:

@interface BaseClass (MyProtocolDefaults) <MyProtocol>
@end

...

@implementation BaseClass (MyProtocolDefaults)
- (void)execute1
{
    ...
}
@end

如果您这样做,我仍然建议您仍不要在子类中重新采用该协议(即使它是完全合法的),而应通过导入BaseClass类别来“拾取”该协议:

#import "BaseClass.h"
#import "BaseClass+MyProtocolDefaults.h"

@interface DogClass : BaseClass
// this class adopts <MyProtocol> indirectly through the BaseClass category

答案 1 :(得分:0)

据我所知,我将尝试解释:

1)我同意您宁愿将基类订阅到协议中,而不是订阅每个孩子。 2)如果要通过协议使用多态,则应携带:

- (void)commonCalculator;

方法适用于协议,而不适用于基类。然后,您将能够在所需的位置实现所需的逻辑,例如在基类中。只是在那里实现此方法。

3)我也想提一个建议: 苹果工程师喜欢使用类集群模式,这是工厂模式的特例。因此,在.h文件中,您将具有以下内容:

@protocol MyProtocol<NSObject>

@property (assign, nonatomic, readonly) NSInteger commonValue;
- (void)commonCalculator;

- (void)execute;

@end

typedef NS_ENUM(NSUInteger, BaseClassType) {
    BaseClassTypeA,
    BaseClassTypeB,
    BaseClassTypeC
};

@interface BaseClass: NSObject<MyProtocol>

- (instancetype)initWithType:(BaseClassType)type;

@end

@interface SubclassA: BaseClass
@end

@interface SubclassB: BaseClass
@end

@interface SubclassC: BaseClass
@end

在您的代码中,您将仅使用基类的实例,但实际上,它将是具体子类的实例。因此,.m文件的实现将如下所示:

@implementation BaseClass

- (instancetype)initWithType:(BaseClassType)type {
    switch (type) {
        case BaseClassTypeA: {
            self = [[SubclassA alloc] init];
        }
        case BaseClassTypeB: {
            self = [[SubclassB alloc] init];
        }
        case BaseClassTypeC: {
            self = [[SubclassC alloc] init];
        }
    }
    return self;
}

@end

如您所见,这说明了如何使用策略模式的示例,(因为它是,我们有几种策略,并且相对于实例化一种策略,将执行所需的方法,因此,每种策略都封装了某种算法在幕后,但它隐藏在通用接口后面)与类集群模式(这是Factory模式的特殊情况)结合使用。您应该记住,对于与战略协议和谐地集成到您的应用程序设计中的策略协议,没有严格的标准。 这种方法使您的应用程序设计非常优美且易于理解。