繁体   English   中英

Objective-C 中的策略模式

[英]Strategy pattern in Objective-C

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

@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 中使用通用代码?

如果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)我同意您宁愿将基类订阅到您的协议,而不是订阅每个孩子。 2)如果您要通过协议使用多态性,您应该携带:

- (void)commonCalculator;

方法到协议,而不是基类。 然后你将能够在需要的地方实现所需的逻辑,比如在基类中。 只需在那里实现这个方法。

3)另外我想给一个建议:Apple工程师喜欢使用Class Cluster模式,这是工厂模式的一个特例。 因此,在 .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

如您所见,这说明了如何使用策略模式的示例,(因为就是这样,我们有几种策略,并且相对于实例化的策略将执行所需的方法,因此,每个策略都在引擎盖下封装了一些算法,但它隐藏在公共接口后面)与类集群模式(这是工厂模式的特殊情况)相结合。 您应该记住,只要它与您的应用程序设计和谐地集成,您将在策略协议中引入多少方法并没有任何严格的标准。 这种方法使您的应用程序设计非常优雅且易于理解。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM