简体   繁体   English

Objective-C 中的策略模式

[英]Strategy pattern in Objective-C

I wrote a sample code strategy design 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

In addition, I want to create a BaseClass to implement a common logic.另外,我想创建一个 BaseClass 来实现一个通用逻辑。
But, there is no way to access BaseClass from MyProtocol type.但是,无法从 MyProtocol 类型访问 BaseClass。

For example例如

- (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];
    }
}

Is there a way to use a common code in BaseClass while using a strategy pattern?有没有办法在使用策略模式时在 BaseClass 中使用通用代码?

If BaseClass implements default behavior for <MyProtocol> , then BaseClass should adopt and implement <MyProtocol> .如果BaseClass实现了<MyProtocol>默认行为,那么BaseClass应该采用并实现<MyProtocol>

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

The subclasses will then inherit that protocol:然后子类将继承该协议:

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

The good news is the subclasses can call [super execute1] and the compiler won't complain if you try to use or pass an instance of BaseClass as id<MyProtocol> .好消息是子类可以调用[super execute1]并且如果您尝试使用或传递BaseClass的实例作为id<MyProtocol>编译器不会抱怨。

Now if, for some unexplained reason, you must to separate the code for the superclass implementation of BaseClass <MyProtocol> into its own module, it's possible to do that by creating a category of BaseClass that adopts and implements your default implementation there:现在,如果出于某种无法解释的原因,您必须将BaseClass <MyProtocol>的超类实现的代码分离到它自己的模块中,则可以通过创建一个采用并实现您的默认实现的BaseClass类别来做到这一点:

@interface BaseClass (MyProtocolDefaults) <MyProtocol>
@end

...

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

If you do this, I'd still suggest that you still not re-adopt the protocol in your subclasses (even though it's perfectly legal), but instead "pick up" the protocol by importing the BaseClass category:如果你这样做,我仍然建议你仍然不要在你的子类中重新采用协议(即使它是完全合法的),而是通过导入BaseClass类别来“选择”协议:

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

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

As far as I understand you correctly, I'm gonna try to explain:就我理解的正确而言,我将尝试解释:

1) I agree that you'd rather subscribe your base class to your protocol instead of subscribing each child. 1)我同意您宁愿将基类订阅到您的协议,而不是订阅每个孩子。 2) If you gonna use polymorphism by protocol you should bring the: 2)如果您要通过协议使用多态性,您应该携带:

- (void)commonCalculator;

method to the protocol, not to base class.方法到协议,而不是基类。 Then you will be able to implement needed logic in needed place, like in base class.然后你将能够在需要的地方实现所需的逻辑,比如在基类中。 Just implement this method there.只需在那里实现这个方法。

3) Also I would like to give an advise: Apple engineers like to use Class Cluster pattern, it's a particular case of factory pattern. 3)另外我想给一个建议:Apple工程师喜欢使用Class Cluster模式,这是工厂模式的一个特例。 So, in the .h file you will have something like this:因此,在 .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

And through over your code you will be working only with instances of base class, but under the hood it will be instances of concrete subclass.通过你的代码,你将只使用基类的实例,但在引擎盖下它将是具体子类的实例。 So, the implementation of your .m file will look like:因此,您的 .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

As you can see, this illustrates an example of how to use strategy pattern, (because that is it, we have several strategies and relative to which one is instantiated the needed method will be executed, so, each strategy incapsulates some algorithm under the hood, but it hides behind common interface) in combination with Class Cluster pattern (which is the particular case of Factory pattern).如您所见,这说明了如何使用策略模式的示例,(因为就是这样,我们有几种策略,并且相对于实例化的策略将执行所需的方法,因此,每个策略都在引擎盖下封装了一些算法,但它隐藏在公共接口后面)与类集群模式(这是工厂模式的特殊情况)相结合。 You should remember that there are no any strict standards of how many methods you will bring into the strategy protocol as far as it harmoniously integrates with your app design.您应该记住,只要它与您的应用程序设计和谐地集成,您将在策略协议中引入多少方法并没有任何严格的标准。 This approach makes you app design very graceful and understandable.这种方法使您的应用程序设计非常优雅且易于理解。

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

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