设计模式之感悟和实践1

栏目: IOS · 发布时间: 5年前

内容简介:设计模式可以说是老生常谈的一个知识点。工作这么多年来也是陆陆续续看过几本书。比如《大话设计模式》、《Head First 设计模式》,这两本书是前期接触比较多,而且质量还是不错的两本书,不过之前看的感觉有点像猪八戒吃人参果——食而不知其味。很多时候有的人在写代码的过程中对设计模式并不为然。像本人是做APP开发的,APP开发结束后,迭代和新增业务逻辑不是很多的话,确实以前写成啥样其实真的无所谓。直到近来接手了公司一个历史悠久的主项目,由于业务的发展,业务逻辑越来越多,改动越来越大,每次新增业务都举步维艰,让

背景

设计模式可以说是老生常谈的一个知识点。工作这么多年来也是陆陆续续看过几本书。比如《大话设计模式》、《Head First 设计模式》,这两本书是前期接触比较多,而且质量还是不错的两本书,不过之前看的感觉有点像猪八戒吃人参果——食而不知其味。

很多时候有的人在写代码的过程中对 设计模式 并不为然。像本人是做APP开发的,APP开发结束后,迭代和新增业务逻辑不是很多的话,确实以前写成啥样其实真的无所谓。直到近来接手了公司一个历史悠久的主项目,由于业务的发展,业务逻辑越来越多,改动越来越大,每次新增业务都举步维艰,让我深刻的体会到了设计模式的优点和威力。

近来正好又重新拾起设计模式在看另外一本书《设计模式之禅》这本书,这本书较之其他两本书感觉比较接地气吧。这次看着很慢,每个模式都在细细的琢磨,再加上之前项目的经验和这次槽糕的老项目,收获比较多,感悟也比较深。

设计原则

要说设计模式,设计原则是必不可缺少的。如果单单去看这几个原则,其实一眼就能看完。原则只是原则,是要尽量保持,而不是必须保持的哦!所以不能一言而论,根据业务和情景懂得变通。

单一原则

应该有且仅有一个原因引起类的变更。

这个原则在使用的过程中要做到适度,如果过度使用的话,可以将一个类中所有的方法都对应做成一个类。 其实在使用过程中说白了就是根据业务或某一方面将功能归类,同一功能的放在一起,声明一个接口。

设计模式之感悟和实践1

比如上图,我们根据用户的属性和用的行为,划分为两个接口。

根据以上例子单一原则的有点也是显而易见:类的复杂性降低,可维护性高。

里氏替换原则

只要父类出现的地方子类就可以出现,而且替换为子类也不会产生任何错误或异常,使用这可能根本就不需要知道是父类还是子类。但是,反过来就不行了。

这个原则用到的其实就是类的继承,在一些情况下继承的优点不言而喻,不过在项目中不要随便使用继承。继承是可以用其他设计模式替换的,比如装饰模式等。 继承具有以下缺点:

  • 继承是侵入性的。只要继承,就必须拥有父类的所有属性和方法。这个危害性还是挺大的!

  • 降低了代码耦合性。子类必须拥有父类的属性和方法,让子类自由的世界中多了些约束

  • 增加了耦合性。当父类的常量、变量和方法被修改时,需要考虑子类的修改,而且在缺乏规范的环境下,这种修改时毁灭性的。

如果子类不能完整地实现父类的方法,或者父类的某些方法在子类中已经发生"畸形",则建议断开父子继承关系,采用依赖、聚集、组合等关系代替继承

依赖倒置原则

高层模块不应该依赖底层模块,两者都应该依赖其抽象(接口或实现类)。一句大白话就是面向接口编程

也就是APP开发过程中,只要有接口文档,我们就可以实现APP啦,不需要后台人员api的实现。也可以这么理解。

接口隔离原则

建立单一接口,不要建立臃肿庞大的接口。

单一职责要求的是类和接口职责单一,注重的是职责,这是业务逻辑上的划分,而接口隔离原则要求接口的方法尽量少。

例如一个接口的职责可能包含10个方法,这10个方法都放在一个接口中,并且提供给多个模块访问,各个模块按照规定的权限来访问,在系统外通过文档约束“不使用的方法不要访问”,按照单一职位原则是允许的,按照接口隔离原则是不允许的,因为它要求“尽量使用多个专门的接口”。就是指提供给每个模块的都应该是单一接口,提供给几个模块就应该有几个接口,而不是建议一个庞大的臃肿的接口。 我们在使用组件化的过程中,由于模块间的调用,每个模块都对外声明一个公共接口,这时候其实就违背了接口隔离原则。比如我们可以按照同一层级调用声明一个接口,不同层级的调用声明一个接口。

迪米特法则

一个对象应该对其他对象有最少的了解

  • 只和朋友交流 朋友:出现在成员变量、方法的输入输出参数中的类称为成员朋友类,而出现在方法体内的类不属于朋友类 比如我们在方法中使用了一个局部对象变量,这就违背了这个原则

  • 是自己的就是自己的 如果一个方法放在本类中,既不增加类间关系,也对本类不产生负面影响,那就放置在本类中。

开闭原则

一个软件实体如类、模块和函数应该对外扩展开放,对修改关闭。即软件实体应该对扩展开放,对修改关闭,其含义是说一个软件实体应该通过扩展来实现变化,而不是通过修改已有的代码来实现变化。

上边啰嗦一下设计模式的原则,其实我们在项目实践中也就是因为代码违背了其中的原则,然后进行改进,进而演化出设计模式。

所以设计模式都是基于以上原则产生的。

场景使用

这次我们介绍的是责任链模式

责任链模式的重点是在“链”上,由一条链去处理相似的请求在链中决定谁来处理这个请求,并返回相应的结果。

通过这个定义不知道大家有没有能想到应用的场景呢?

像在我们工程中由于业务场景的复杂性,就存在大量的 if...else 判断。这样的逻辑导致业务交叉在一起,导致每个业务不清晰,扩展起来不是很方便,并且在iOS中会导致 UIViewController 臃肿。

这个时候我们可以引入责任链模式,调用方不用关心真正的业务处理,只要关心业务分类就行,真正的业务交给一个实体类来处理。

首先我们看一下责任链模式通用类图

这个看着可能有点不知道所以然,所以我们来个实例讲解一下,相信看了之后就会恍然大悟。

这是demo所有的类图

ActionClickProtocol

@protocol ActionClickProtocol - (void)handleClick;
- (void)setNext:(id)actionClickHandle;
@end

typedef NS_ENUM(NSUInteger, HandleType) {
    CLICK1,
    CLICK2,
};

ActionClickHandle

@interface ActionClickHandle : NSObject@property (nonatomic,assign)HandleType type;
@property (nonatomic,strong)ActionClickHandle *nextHandle;
@end


@implementation ActionClickHandle
- (void)handleClick {
    NSLog(@"共有的处理方法");
}

- (void)setNext:(nonnull id)actionClickHandle {
    self.nextHandle = actionClickHandle;
}
@end

ActionClickEvent1

@interface ActionClickEvent1 : ActionClickHandle
@end

@implementation ActionClickEvent1
-(void)handleClick{
    NSLog(@"事件1的处理");
}
@end

ActionClickEvent2

@interface ActionClickEvent2 : ActionClickHandle
@end

@implementation ActionClickEvent2
-(void)handleClick{
   NSLog(@"事件2的处理");
}
@end

MyHandle这个类是核心对外使用的类

@interface MyHandle : NSObject
- (instancetype)initWithType:(HandleType)type;
- (void)handleClick;
@end

@interface MyHandle()
@property (nonatomic,assign)HandleType type;
@property (nonatomic,strong)ActionClickHandle *nextHandle;
@property (nonatomic,strong)ActionClickEvent1 *event1;
@property (nonatomic,strong)ActionClickEvent2 *event2;
@end
@implementation MyHandle
- (instancetype)initWithType:(HandleType)type{
    self = [super init];
    if (self) {
        _type = type;
        _event1 = [[ActionClickEvent1 alloc] init];
        _event1.type = CLICK1;
        _event2 = [[ActionClickEvent2 alloc] init];
        _event2.type = CLICK2;
        [_event1 setNextHandle:_event2];
        self.nextHandle = _event1;
    }
    return self;
}
- (void)handleClick{
    if (self.nextHandle.type==self.type) {
        [self.nextHandle handleClick];
    }else{
        while (self.nextHandle.type!=self.type) {
            self.nextHandle = self.nextHandle.nextHandle;
        }
        [self.nextHandle handleClick];
    }
}

@end

使用范例:

MyHandle *myHandle = [[MyHandle alloc] initWithType:CLICK2];
 
[myHandle handleClick];

我们在使用的过程中可以面向model开发,将model传入 handleClick 方法中。type则是mode中根据接口数据的返回对应的不同类型。

这种使用方法完全可以避免if...else的使用,并且业务逻辑很清晰。

总结

其实项目使用过程中,关键一点还是要去发现那块代码会一直变,将经常变换的代码进行设计模式的封装,则以后的代码扩展是非常的方便

我的博客

我的博客


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Think Python

Think Python

Allen B. Downey / O'Reilly Media / 2012-8-23 / GBP 29.99

Think Python is an introduction to Python programming for students with no programming experience. It starts with the most basic concepts of programming, and is carefully designed to define all terms ......一起来看看 《Think Python》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具