如何优雅地实现策略模式

作者: dreamCatcher | 来源:发表于2015-04-27 00:25 被阅读4087次

    在 XMind iOS 版开发过程中, 需要对不同的布局方式选择不同的类来进行布局,所以需要用到策略模式来处理。在开发过程中,找到了一种还不错的解决方式。

    在 XMind 思维导图中,每一个 topic 都包含一个布局的名称,被称为 structure,我们为各种布局设计了不同的布局类来布局,这里称为 layout

    最初的处理方法

    最开始开发的过程中,我在 controller 中定义了一个 NSDictionary,用于存放 structureNamelayout 的对应关系。

    @property (nonamatic, strong) NSDictionary *structureDict;
    
    - (instance)init {
        self = [super init];
        _structureDict = @{ structureNameA : LayoutA,
                            structureNameB : LayoutB,
                            structureNameC : LayoutC,
                            structureNameD : LayoutD,
                            structureNameE : LayoutE};
    }
    

    这种方式的确可以避免太多的 if else 的选择结构。但是, controller还是必须要知道各个策略类,假如 structureName 有变化,或者新增一种策略 (layout class) 的时候,需要去修改 controller 的策略 structureDict,并且需要导入新的策略类。

    解耦的处理方法

    后来经 @Frank 提醒,找到了一种更好的方式来处理此类策略选择问题。每个策略子类自行将自己以及对应的 strucutreName 作为 key 注册到共同父类 LayoutBase class 中的字典中去。这样以来,策略有变化 (如 structureNameA 需要选择策略 LayoutC ) 或者新增策略的话,只需要继续给 LayoutBase 加子类即可,不需要需要其他类,实现了解耦合。示例代码如下,

    在父类中提供注册和查询的类方法。

    @implementation LayoutBase
    
    static NSMutableDictionary *subClassDict = nil;
    
    + (void)registerLayout:(Class)layout withKey:(NSString *)key {
        if (subClassDict == nil)
        {
            subClassDict = [[NSMutableDictionary alloc] init];
        }
        [subClassDict setObject:layout forKey:key];
    }
    
    + (Class)layoutClassWithKey:(NSString *)key {
        if ([subClassDict objectForKey:key]) {
            Class class = [subClassDict objectForKey:key];
            return class;
        }
        return nil;
    }
    
    @end
    

    子类则需要在 load 的方法中,将自己注册到 subClassDict 中。

    @implementation LayoutA
    
    + (void)load {
        [LayoutBase registerLayout:self withKey:structureNameA];
    }
    
    @end
    

    什么是 load 方法?

    上述处理方法中我们用到了类的 load 方法。load 方法是一个特殊类方法。
    runtime 会在程序运行一开始对所有引用的 class 调用其 load 方法一次。所以可以利用这个方法进行一些预处理工作。官方的介绍,

    Invoked whenever a class or category is added to the Objective-C runtime; implement this method to perform class-specific behavior upon loading.

    详情请移步:Apple 官方介绍

    还可参考:Ider的博客 Objective C类方法load和initialize的区别

    进一步优化

    一般情况下,策略选择不会是 key 和 class 一一对应着么简单。可能还要考虑各种因素加入算法进行策略选择。把策略选择这个职责交给一个单独的类来处理,我们这里把它叫做 layoutSelector。Controller 在选择策略时,发消息给 layoutSelector,然后由 layoutSelector 进行处理将选好的策略返回。

    Layout *layout = [controller installLayoutWithConditions: (NSDictionary *)conditionsDict];
    

    欢迎来我的个站逛逛: http://alexyu.me/

    相关文章

      网友评论

        本文标题:如何优雅地实现策略模式

        本文链接:https://www.haomeiwen.com/subject/nwkotttx.html