1.面对对象的六大设计原则
单一职责:一个类只做一种类型责任,当这个类需要承当其他类型的责任的时候,就需要分解这个类。不过在现实开发中,这个原则是最不可能遵守的,因为每个人对一个类的哪些功能算是同一类型的职责判断都不相同。(网络请求类)
开放封闭原则:软件实体应该是可扩展,而不可修改的。也就是说,你写完一个类,要想添加功能,不能修改原有类,而是想办法扩展该类。有多种设计模式可以达到这一要求。(继承,分类等)
里氏替换原则:当一个子类的实例应该能够替换任何其超类的实例时,它们之间才具有
is-A
关系。也就是说接口或父类出现的地方,实现接口的类或子类可以代入,这主要依赖于多态和继承。(子类对象能够替换父类对象,而程序执行效果不变)迪米特法则(最少知道原则):一个对象应该对尽可能少的对象有接触,也就是只接触那些真正需要接触的对象。
接口分离原则:不能强迫用户去依赖那些他们不使用的接口。换句话说,使用多个专门的接口比使用单一的总接口总要好。 不要提供一个大的接口包括所有功能,应该根据功能把这些接口分割,减少依赖(同一职责的协议一起,例如
UITableViewDelegate
和UITableViewDataSource
)依赖倒置原则:高层模块不应该依赖于低层模块,二者都应该依赖于抽象;抽象不应该依赖于细节,细节应该依赖于抽象。(依赖抽象,例如签订协议)
2.什么是设计模式?在软件开发中,经过验证的,用于解决在特定环境下,重复出现的特定的问题的解决方案。
- 软件开发:其实各行各业都有模式可以套用,这里的设计模式指的是在软件开发领域
- 经过验证的:必须是经过大家公认和验证过的解决方案才算得上是设计模式,而不是每个人随便总结的解决方案都能算
- 特定环境:必须是在某个特定环境才可以使用该设计模式,因为不同的环境,就算同样的问题,解决方案也不同,所以不能脱离环境去谈使用设计模式
- 重复出现:因为只有重复出现的问题才有必要总结经验,形成固定的解决方案,再次遇到这样的问题就不用从头开始寻找解决方案,而是直接套用就可以了。
- 特定问题:软件开发领域没有银弹,不要指望一种设计模式就能包治百病。每种模式只是针对特定问题的解决方案,所以不要迷信设计模式,滥用设计模式。
3.常见的设计模式有23种,根据目的,我们可以把模型分为三类:创建型,结构型,行为型
- 创建型设计模式:创建型模式与对象的创建有关
- 结构型设计模式:结构型模式处理类和对象的组合
- 行为型设计模式:行为型设计模式对类或对象怎样交互和怎么分配职责进行描述
4.创建型
-
Abstract Factory
抽象工厂模式- 简单工厂模式(
Simple Factory Pattern
):专门定义一个类(工厂类)来负责创建其他类的实例。可以根据创建方法的参数来返回不同类的实例,被创建的实例通常都具有共同的父类。(总结来说,其实就是把一大堆的if-else判断由业务层,放到了工厂类里面)
- (PhoneFactory *)sellPhone:(NSString *)type{ if ([type isEqualToString:@"IPhone"]) { IPhone *phone = [IPhone new]; [phone sellPhone]; return phone; }else if ([type isEqualToString:@"MIPhone"]){ MIPhone *phone = [MIPhone new]; [phone sellPhone]; return phone; }else if ([type isEqualToString:@"HWPone"]){ HWPhone *phone = [HWPhone new]; [phone sellPhone]; return phone; } return nil; }
//苹果手机 - (void)sellPhone{ NSLog(@"售卖苹果手机"); } //小米手机 - (void)sellPhone{ NSLog(@"售卖小米手机"); } //华为手机 - (void)sellPhone{ NSLog(@"售卖华为手机"); } //客户端调用 PhoneFactory *faceory = [PhoneFactory new]; [faceory sellPhone:@"IPhone"];
-
工厂方法模式(
Factory Method Pattern
)又称为工厂模式,工厂父类负责定义创建产品对象的公共接口,而工厂子类则负责生成具体的产品对象,即通过不同的工厂子类来创建不同的产品对象。(抽象工厂-具体工厂-具体产品,比简单工厂多了一层继承)工厂方法模式的适用场景与简单工厂类似,都是创建数据和行为比较类似的对象。但是和简单工厂不同的是:在工厂方法模式中,因为创建对象的责任移交给了抽象工厂的子类,因此客户端需要知道其所需产品所对应的工厂子类,而不是简单工厂中的参数
-
抽象工厂模式(Abstract Factory Pattern):提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。(顶层是@protocol接口创建抽象工厂,层级和工厂模式一样)
有时候我们需要一个工厂可以提供多个产品对象,而不是单一的产品对象。比如系统中有多于一个的产品族,而每次只使用其中某一产品族,属于同一个产品族的产品将在一起使用
-
三个模式的对比
- 抽象工厂模式和工厂模式 工厂模式针对单独产品的创建,而抽象工厂注重一个产品系列的创建。如果产品系列只有一个产品的 话,那么抽象工厂就退换到工厂模式了。在抽象工厂中使用工厂方法来提供具体实现,这个时候他们联 合使用。
- 工厂模式和简单工厂 两者非常类似,都是用来做选择实现的。不同的地方在于简单工厂在自身就做了选择实现。而工厂模式 则是把实现延迟到子类执行。如果把工厂方法的选择实现直接在父类实现,那么此时就退化为简单工厂 模式了。
- 简单工厂和抽象工厂 简单工厂用于做选择实现,每个产品的实现之间没有依赖关系。而抽象工厂实现的一个产品系列,相互 之间有关联。这是他们的区别
- 简单工厂模式(
作为一个开发者,有一个学习的氛围跟一个交流圈子特别重要,这有个iOS交流群:642363427,不管你是小白还是大牛欢迎入驻 ,分享BAT,阿里面试题、面试经验,讨论技术,iOS开发者一起交流学习成长!
- 创建者模式(
Builder Pattern
):也叫生成器模式,它将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。(适用于复杂对象创建,简单的就不要用了,比如SDWebImage
的SDWebImageDownloader
和SDWebImageDownloaderOperation
就是director
和builder
之间的关系。前者不负责具体的下载操作,只负责管理builder
,builder
负责图片的具体下载。)
建造者模式包含4个成员:
- 抽象建造者(Builder):生成器接口,定义创建一个Product对象所需要的各个部件的操作
- 具体建造者(ConcreteBuilder):具体的生成器实现,实现各个部件的创建,并负责组装Product对象的各个部件,同时还提供一个让用户获取组装完成后的产品对象的方法
- 指挥者(Director): 主要用来使用Builder接口,以一个统一的过程来构建所需要的Product对象
- 产品角色(Product): 表示生成器构建的复杂对象,包含多个部件
protocol DesignProtocol {
//设计图纸类型
func DesignDrawings()
}
protocol ConstructionProtocol {
//施工队 施工
func Construction()
}
protocol BuilderProtocol {
// 返回构建的对象
func build()->Self
}
class Design:DesignProtocol,BuilderProtocol {
func DesignDrawings() {
print("设计图纸")
}
func build() -> Self {
return self
}
}
class A_Design:Design {
override func DesignDrawings() {
print("设计图纸是大别墅")
}
}
class B_Design:Design {
override func DesignDrawings() {
print("设计图纸是小洋楼")
}
}
class C_Design:Design {
override func DesignDrawings() {
print("设计图纸是茅草屋")
}
}
class Construction: ConstructionProtocol,BuilderProtocol {
func Construction() {
print("施工队")
}
func build() -> Self {
return self
}
}
class A_Construction:Construction {
override func Construction() {
print("A 级施工队")
}
}
class B_Construction:Construction {
override func Construction() {
print("B 级施工队")
}
}
class C_Construction:Construction {
override func Construction() {
print("C 级施工队")
}
}
class Builder {
var design:Design?
var construction:Construction?
func buildAllParts(){
design = design?.build()
construction = construction?.build()
design?.DesignDrawings()
construction?.Construction()
print("房子造出来了")
}
}
//指挥者调用
let build = Builder()
build.design = A_Design()
build.construction = B_Construction()
build.buildAllParts()
-
原型模式(
Prototype Pattern
): 使用原型实例指定待创建对象的类型,并且通过复制这个原型来创建新的对象。(说到底就是copy
)iOS
已经提供了一个协议NSCopying&NSMutableCopying
协议,我们只需要实现NSCopying&NSMutableCopying
协议就可以了 -
单例模式 (
Singleton Pattern
):单例模式确保某一个类只有一个实例,并提供一个访问它的全剧访问点。在应用这个模式时,单例对象的类必须保证只有一个实例存在。许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为。比如在APP开发中我们可能在任何地方都要使用用户的信息,那么可以在登录的时候就把用户信息存放在一个文件里面,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息。这种方式简化了在复杂环境下的配置管理
5.结构型
-
适配器模式 (
Adapter Pattern
) :将一个接口转换成客户希望的另一个接口,使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。适配器模式的别名是包装器模式(Wrapper
),是一种结构型设计模式。(Model
再用代理分离出来一个类控制数据,解耦View
和Model
的关联,优点是解耦合,让视图类不合数据类产生耦合,使视图类更加独立。 新增加数据类的时候不需要修改视图类。缺点是又增加了许多类,麻烦)定义解读:适配器模式又分为对象适配器和类适配器两种。
- 对象适配器:利用组合的方式将请求转发给被适配者。
- 类适配器:通过适配器类多重继承目标接口和被适配者,将目标方法的调用转接到调用被适配者的方法。
-
桥接模式 (
Simple Factory Pattern
):将抽象部分与它的实现部分分离,使它们都可以独立地变化。抽象类(
Abstraction
):抽象类维护一个实现部分的对象的引用,并声明调用实现部分的对象的接口。扩展抽象类(
RefinedAbstraction
):扩展抽象类定义跟实际业务相关的方法。实现类接口(
Implementor
):实现类接口定义实现部分的接口。具体实现类(
ConcreteImplementor
):具体实现类具体实现类是实现实现类接口的对象
假设要实现一个给客户发送提示消息的功能,发送的消息类型可分为:普通消息、加急消息、特加急消息等等,而每种消息的发送的方式一般有:系统内推送、手机短信、电子邮件等等
- 抽象类就是消息的抽象类
- 扩展抽象类就是继承消息抽象类的子类:各种消息
- 实现接口就是发送方式接口
- 具体实现类就是继承发送方式类:系统内推送、手机短信、电子邮件
代码实现
//消息类型抽象类
#import
#import "messageImplement.h"
NS_ASSUME_NONNULL_BEGIN
@interface abstractMessage : NSObject
@property(strong,nonatomic)id messageIm;
//初始化
- (instancetype)initWithImplement:(id)implement;
//发送消息
- (void)send:(NSString*)message;
@end
NS_ASSUME_NONNULL_END
------------------------------------
@implementation abstractMessage
- (instancetype)initWithImplement:(id)implement
{
self = [super init];
if (self) {
self.messageIm = implement;
}
return self;
}
//发送消息
- (void)send:(NSString*)message{
}
@end
//具体消息类型
#import "abstractMessage.h"
@interface commonMessage : abstractMessage
@end
-----------------
#import "commonMessage.h"
@implementation commonMessage
//发送消息
- (void)send:(NSString*)message{
NSString *msg = [NSString stringWithFormat:@"普通消息:%@",message];
[self.messageIm sendMessage:msg];
}
@end
//消息发送接口
#import
@protocol messageImplement
-(void)sendMessage:(NSString *)message;
@end
//具体的消息发送方式
#import "messageImplement.h"
@interface messageEmail : NSObject
@end
------------------------
#import "messageEmail.h"
@implementation messageEmail
-(void)sendMessage:(NSString *)message{
NSLog(@"使用Email方式发送消息,消息内容:%@", message);
}
@end
// 客户端调用
messageEmail *email = [messageEmail new];
abstractMessage *msg = [[commonMessage alloc]initWithImplement:email];
[msg send:@"桥接模式测试"];
- 组合模式 将对象组合成树形结构以表示 “ 部 分 -整 体 ” 的层次结构 组合模式使得用户 对单个对象和组合对象的使用具有一致性。(在Cocoa Touch框架中,UIView被组织成一个组合结构。每个UIView的实例可以包含UIView的其他实例,形成统一的树形结构。让客户端对单个UIView对象和UIView的组合统一对待。)
组合部件(Component):它是一个抽象角色,为要组合的对象提供统一的接口。
叶子(Leaf):在组合中表示子节点对象,叶子节点不能有子节点。
合成部件(Composite):定义有枝节点的行为,用来存储部件,实现在Component接口中的有关操作,如增加(Add)和删除(Remove)
- 装饰者模式(
Decorator
):动态的给一个对象添加一些额外的职责,就增加功能来说,装饰者模式比生成子类更加灵活(其实在iOS里面已经为我们提供了类似装饰器模式的功能的方法:Category
)
抽象构件(Component):抽象构件定义一个对象(接口),可以动态地给这些对象添加职责
具体构件(Concrete Component):具体构件是抽象构件的实例。
装饰(Decorator):装饰类也继承于抽象构件,它持有一个具体构件对象的实例,并实现一个与抽象构件接口一致的接口。
具体装饰(Concrete Decorator):具体装饰负责给具体构建对象实例添加上附加的责任。
- 外观模式(
Facade Pattern
):外观模式定义了一个高层接口,为子系统中的一组接口提供一个统一的接口。外观模式又称为门面模式,它是一种结构型设计模式模式。(总而言之就是构建一个统一的接口来整合,降低依赖, 比如AFNetworking
对于NSURLSession
的不同系统版本的处理,利用外观模式提供一个统一的接口。)
享元模式(
Flyweight Pattern
):运用共享技术复用大量细粒度的对象,降低程序内存的占用,提高程序的性能。主要应用于有大量 重复的对象 的时候(UIImage内部API已经做过缓存了,内部也是实现了享元模式)-
代理模式
远程代理(
Remote Proxy
):为一个位于不同的地址空间的对象提供一个本地的代理对象,这个不同的地址空间可以是在同一台主机中,也可是在另一台主机中,远程代理又称为大使(Ambassador)。虚拟代理(
Virtual Proxy
):如果需要创建一个资源消耗较大的对象,先创建一个消耗相对较小的对象来表示,真实对象只在需要时才会被真正创建。(虚拟代理主要用来做延迟加载,一个tableview
列表需要从网络下载很多图片显示,如果等到全部下载完毕再显示,用户体验会很不好。一个替代方法就是首次加载时显示一个占位图,当后台线程下载完图片,再用真实图片去替代原来的占位图。这就是上面说的延迟加载)保护代理(
Protect Proxy
):控制对一个对象的访问,可以给不同的用户提供不同级别的使用权限.缓冲代理(
Cache Proxy
):为某一个目标操作的结果提供临时的存储空间,以便多个客户端可以共享这些结果。智能引用代理(
Smart Reference Proxy
):当一个对象被引用时,提供一些额外的操作,例如将对象被调用的次数记录下来等。
5.行为型
- 责任链模式(
Chain of Responsibility
):使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系。将这个对象连城一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。(iOS中的响应链就是按照责任链模式设计的)
Handler:定义这人的接口,通常在这里定义处理请求的方式,可以在这里实现后续链
ConcreteHandler:实现职责的类,在这个类中,实现对它职责范围内请求的处理,如果不处理,就继续转发请求给后继者
Client:职责链的客户端,向链上的具体对象提交请求,让职责链负责处理
- 命令模式(
Command Pattern
):在软件系统中,“行为请求者”与“行为实现者”通常呈现一种“紧耦合”。但在某些场合,比如要对行为进行“记录、撤销/重做、事务”等处理,这种无法抵御变化的紧耦合是不合适的。在这种情况下,如何将“行为请求者”与“行为实现者”解耦?将一组行为抽象为对象,实现二者之间的松耦合。这就是命令模式(Target-Action,NSInvocation都是命令模式)
解释器模式(
Interpreter Pattern
):定义一个语言的文法,并且建立一个解释器来解释该语言中的句子,这里的“语言”是指使用规定格式和语法的代码。解释器模式是一种类行为型模式。(比如判断邮件地址、电话号码、证件号码是否是正确的正则表达式,就是应用了解释器模式。)迭代器模式(
Iterator Pattern
):提供一种方法来访问聚合对象,而不用暴露这个对象的内部表示,其别名为游标 (Cursor)。迭代器模式是一种对象行为型模式。(NSEnumerator)-
中介者模式(
Mediator Pattern
):用一个中介对象(中介者)来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。中介者模式又称为调停者模式,它是一种对象行为型模式,中介者模式是“迪米特法则”的一个典型应用。( iOS组件化)Mediator
(抽象中介者):它定义一个接口,该接口用于与各同事对象之间进行通信。ConcreteMediator
(具体中介者):它是抽象中介者的子类,通过协调各个同事对象来实现协作行为,它维持了对各个同事对象的引用。Colleague
(抽象同事类):它定义各个同事类公有的方法,并声明了一些抽象方法来供子类实现,同时它维持了一个对抽象中介者类的引用,其子类可以通过该引用来与中介者通信。ConcreteColleague
(具体同事类):它是抽象同事类的子类;每一个同事对象在需要和其他同事对象通信时,先与中介者通信,通过中介者来间接完成与其他同事类的通信;在具体同事类中实现了在抽象同事类中声明的抽象方法。
-
备忘录模式(
Memento Pattern
):在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样可以在以后将对象恢复到原先保存的状态。它是一种对象行为型模式,其别名为Token。(Cocoa Touch
框架在归档解档、属性列表序列化和CoreData
中采用了备忘录模式。)Originator
(原发器):它是一个普通类,可以创建一个备忘录,并存储它的当前内部状态,也可以使用备忘录来恢复其内部状态,一般将需要保存内部状态的类设计为原发器。Memento
(备忘录):存储原发器的内部状态,根据原发器来决定保存哪些内部状态。备忘录的设计一般可以参考原发器的设计,根据实际需要确定备忘录类中的属性。需要注意的是,除了原发器本身与负责人类之外,备忘录对象不能直接供其他类使用,原发器的设计在不同的编程语言中实现机制会有所不同。Caretaker
(负责人):负责人又称为管理者,它负责保存备忘录,但是不能对备忘录的内容进行操作或检查。在负责人类中可以存储一个或多个备忘录对象,它只负责存储对象,而不能修改对象,也无须知道对象的实现细节。
观察者模式(
Observer Pattern
):定义对象之间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。观察者模式的别名包括发布-订阅(Publish/Subscribe
)模式、模型-视图(Model/View
)模式、源-监听器(Source/Listener
)模式或从属者(Dependents
)模式。观察者模式是一种对象行为型模式。(iOS
中的KVO
、NSNotication
都是观察者模式)状态模式(
State Pattern
):允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。其别名为状态对象(Objects for States
),状态模式是一种对象行为型模式,状态模式用于解决系统中复杂对象的状态转换以及不同状态下行为的封装问题。策略模式(
Strategy Pattern
):定义一系列算法类,将每一个算法封装起来,并让它们可以相互替换,策略模式让算法独立于使用它的客户而变化,也称为政策模式(Policy
)。策略模式是一种对象行为型模式。(在MVC
模式中,控制器决定视图对模型数据进行显示的时机和内容。视图本身知道如何绘图,但需要控制器告诉它要显示的内容。同一个视图如果与不同的控制器合作,数据内容随着不同控制器而不同,这个时候控制器就是视图的策略。)模板方法模式(
Template Method Pattern
):定义一个操作中算法的框架,而将一些步骤延迟到子类中。模板方法模式使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。(在Cocoa Touch
框架中,最常见的UIViewController
,如果需要适配屏幕旋转,那么必须重写各种旋转的方法,比如shouldAutorotat
e就是典型的钩子方法。还有UIView
有个drawRect
方法,如果需要执行定制绘图,那么子类可以重写这个方法来达到效果,drawRect
也是钩子方法。)访问者模式(
Visitor Pattern
):提供一个作用于某对象结构中的各元素的操作表示,它使我们可以在不改变各元素的类的前提下定义作用于这些元素的新操作。访问者模式是一种对象行为型模式。
推荐:
如果你想一起进阶,了解更多不妨添加一下交流群642363427