zoukankan      html  css  js  c++  java
  • 单一职责原则

    单一职责原则

    单一职责原则(Simple responsibility pinciple SRP)

    就一个类而言,应该仅有一个引起它变化的原因,如果你能想到多于一个的动机去改变一个类,那么这个类就具有多于一个的职责。应该把多于的指责分离出去,分别再创建一些类来完成每一个职责。

    单一职责原则是软件设计7大原则之一,其核心思想就是最大限度的提升代码的可复用性

    以下以具体的例子阐述,为何单一职责原则能最大限度的提升代码的可复用性。

    之前写过一篇教程,教大家通过runtime扩展了NSObject的功能支持打印NSObject以及其子类的属性值以及进行字典直接赋值。

    //
    //  NSObject+Properties.h
    //
    //  Created by YouXianMing on 14-9-4.
    //  Copyright (c) 2014年 YouXianMing. All rights reserved.
    //
    
    #import <Foundation/Foundation.h>
    
    @interface NSObject (Properties)
    
    @property (nonatomic, strong) NSDictionary *mapDictionary;
    
    - (void)setDataDictionary:(NSDictionary*)dataDictionary;
    - (NSDictionary *)dataDictionary;
    
    @end
    //
    //  NSObject+Properties.m
    //
    //  Created by YouXianMing on 14-9-4.
    //  Copyright (c) 2014年 YouXianMing. All rights reserved.
    //
    
    #import "NSObject+Properties.h"
    #import <objc/runtime.h>
    
    @implementation NSObject (Properties)
    
    #pragma runtime - 动态添加了一个属性,map属性
    static char mapDictionaryFlag;
    - (void)setMapDictionary:(NSDictionary *)mapDictionary
    {
        objc_setAssociatedObject(self, &mapDictionaryFlag, mapDictionary, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    - (NSDictionary *)mapDictionary
    {
        return objc_getAssociatedObject(self, &mapDictionaryFlag);
    }
    
    #pragma public - 公开方法
    
    - (void)setDataDictionary:(NSDictionary*)dataDictionary
    {
        [self setAttributes:[self mapDictionary:self.mapDictionary dataDictionary:dataDictionary]
                        obj:self];
    }
    
    - (NSDictionary *)dataDictionary
    {
        // 获取属性列表
        NSArray *properties = [self propertyNames:[self class]];
        
        // 根据属性列表获取属性值
        return [self propertiesAndValuesDictionary:self properties:properties];
    }
    
    #pragma private - 私有方法
    
    // 通过属性名字拼凑setter方法
    - (SEL)getSetterSelWithAttibuteName:(NSString*)attributeName
    {
        NSString *capital = [[attributeName substringToIndex:1] uppercaseString];
        NSString *setterSelStr = 
        [NSString stringWithFormat:@"set%@%@:", capital, [attributeName substringFromIndex:1]];
        return NSSelectorFromString(setterSelStr);
    }
    
    // 通过字典设置属性值
    - (void)setAttributes:(NSDictionary*)dataDic obj:(id)obj
    {
        // 获取所有的key值
        NSEnumerator *keyEnum = [dataDic keyEnumerator];
        
        // 字典的key值(与Model的属性值一一对应)
        id attributeName = nil;
        while ((attributeName = [keyEnum nextObject]))
        {
            // 获取拼凑的setter方法
            SEL sel = [obj getSetterSelWithAttibuteName:attributeName];
            
            // 验证setter方法是否能回应
            if ([obj respondsToSelector:sel])
            {
                id value      = nil;
                id tmpValue   = dataDic[attributeName];
                
                if([tmpValue isKindOfClass:[NSNull class]])
                {
                    // 如果是NSNull类型,则value值为空
                    value = nil;
                }
                else
                {
                    value = tmpValue;
                }
                
                // 执行setter方法
                [obj performSelectorOnMainThread:sel
                                      withObject:value
                                   waitUntilDone:[NSThread isMainThread]];
            }
        }
    }
    
    
    // 获取一个类的属性名字列表
    - (NSArray*)propertyNames:(Class)class
    {
        NSMutableArray  *propertyNames = [[NSMutableArray alloc] init];
        unsigned int     propertyCount = 0;
        objc_property_t *properties    = class_copyPropertyList(class, &propertyCount);
        
        for (unsigned int i = 0; i < propertyCount; ++i)
        {
            objc_property_t  property = properties[i];
            const char      *name     = property_getName(property);
            
            [propertyNames addObject:[NSString stringWithUTF8String:name]];
        }
        
        free(properties);
        
        return propertyNames;
    }
    
    // 根据属性数组获取该属性的值
    - (NSDictionary*)propertiesAndValuesDictionary:(id)obj properties:(NSArray *)properties
    {
        NSMutableDictionary *propertiesValuesDic = [NSMutableDictionary dictionary];
        
        for (NSString *property in properties)
        {
            SEL getSel = NSSelectorFromString(property);
            
            if ([obj respondsToSelector:getSel])
            {
                NSMethodSignature  *signature  = nil;
                signature                      = [obj methodSignatureForSelector:getSel];
                NSInvocation       *invocation = [NSInvocation invocationWithMethodSignature:signature];
                [invocation setTarget:obj];
                [invocation setSelector:getSel];
                NSObject * __unsafe_unretained valueObj = nil;
                [invocation invoke];
                [invocation getReturnValue:&valueObj];
                
                //assign to @"" string
                if (valueObj == nil)
                {
                    valueObj = @"";
                }
                
                propertiesValuesDic[property] = valueObj;
            }
        }
        
        return propertiesValuesDic;
    }
    
    // 根据map值替换掉键值
    - (NSDictionary *)mapDictionary:(NSDictionary *)map dataDictionary:(NSDictionary *)data
    {
        if (map && data)
        {
            // 拷贝字典
            NSMutableDictionary *newDataDic = [NSMutableDictionary dictionaryWithDictionary:data];
            
            // 获取所有map键值
            NSArray *allKeys                = [map allKeys];
            
            for (NSString *oldKey in allKeys)
            {
                // 获取到value
                id value = [newDataDic objectForKey:oldKey];
                
                // 如果有这个value
                if (value)
                {
                    NSString *newKey = [map objectForKey:oldKey];
                    [newDataDic removeObjectForKey:oldKey];
                    [newDataDic setObject:value forKey:newKey];
                }
            }
            
            return newDataDic;
        }
        else
        {
            return data;
        }
    }
    
    @end

    以下再来说说为什么有些方法是那么设计的。

    因为是在category中,这个obj是可以替换成self而不用传递任何参数的,但为何还要单独写一个方法来传递obj参数呢?其实道理很简单,如果写成self后可以去掉obj参数,但是呢,这个方法就仅仅限于这个category中使用了,如果你想在其他的地方使用这个方法,你就得修改这个方法并重新弄一个方法,明显,这个方法并不是最基本不依赖于其他类的方法,就比如本例子中category的self,就是它依赖的目标,只有写成支持任意对象时才能算一个符合单一职责原则的方法。

    所以,就在公开的方法中调用这个方法,将self传递给obj即可。

    你仔细查看我写的没有公开的私有方法中,每一个方法都是可以复制粘贴拿到其他类里面直接使用的,它不依赖于任何的外部条件,仅仅是提供一个接口,你提供合适的参数,他就能给你想要的结果。

    单一职责原则的核心就是代码可复用性最强,要将类、方法拆分成最小不可拆分单元,仅此而已哦,很简单:)

     
     
     
  • 相关阅读:
    hihoCoder #1176 : 欧拉路·一 (简单)
    228 Summary Ranges 汇总区间
    227 Basic Calculator II 基本计算器II
    226 Invert Binary Tree 翻转二叉树
    225 Implement Stack using Queues 队列实现栈
    224 Basic Calculator 基本计算器
    223 Rectangle Area 矩形面积
    222 Count Complete Tree Nodes 完全二叉树的节点个数
    221 Maximal Square 最大正方形
    220 Contains Duplicate III 存在重复 III
  • 原文地址:https://www.cnblogs.com/YouXianMing/p/3963975.html
Copyright © 2011-2022 走看看