引言
世上本没有路,走的人多了便成了路。软件本没有什么设计模式,一个问题的解决方案使用的人和次数多了便成为了某一种设计模式..... (个人觉得,😄)
设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。 毫无疑问,设计模式于己于他人于系统都是多赢的,设计模式使代码编制真正工程化,设计模式是软件工程的基石,如同大厦的一块块砖石一样。项目中合理的运用设计模式可以完美的解决很多问题,每种模式在现在中都有相应的原理来与之对应,每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的核心解决方案,这也是它能被广泛应用的原因。
设计模式的分类
总体来说设计模式分为三大类:
创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
设计模式的六大原则
1、开闭原则(Open Close Principle)
开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。
2、里氏代换原则(Liskov Substitution Principle)
里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。 LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。—— From Baidu 百科
3、依赖倒转原则(Dependence Inversion Principle)
这个是开闭原则的基础,具体内容:真对接口编程,依赖于抽象而不依赖于具体。
4、接口隔离原则(Interface Segregation Principle)
这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。还是一个降低类之间的耦合度的意思,从这儿我们看出,其实设计模式就是一个软件的设计思想,从大型软件架构出发,为了升级和维护方便。所以上文中多次出现:降低依赖,降低耦合。
5、迪米特法则(最少知道原则)(Demeter Principle)
为什么叫最少知道原则,就是说:一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。
6、合成复用原则(Composite Reuse Principle)
原则是尽量使用合成/聚合的方式,而不是使用继承。
对于同一种模式,每个人的理解都不同,能解决实际问题才是关键
工厂方法模式
工厂方法模式,顾名思义工厂嘛是生产产品的,生产产品那种方式最快呢?当人是流水线作业嘛,那么怎样才能流水线生产产品呢,这些产品必须要具有相同的生产工艺和生产流程。所以工厂模式就是:工厂模式就是定义创建对象的接口(工厂),让子类决定实例化哪一个类(这些类具有一套相同接口,但是实例化的方式略有差异,即:这些接口的具体实现不同)。这样,类的实例化就推迟到了子类
工厂方法模式又有简单工厂模式(工厂模式的简化版),工厂方法模式,多工厂方法模式(工厂模式的扩展)。下面我们来看看多工厂方法模式:
例子(oc版):
//创建产品的公共操作协议
@protocol DPFactoryProtocol <NSObject>
@optional
- (DPFactoryProductBaseClass *)factoryCreateProduct;
@end
//创建基类并遵守协议
@interface DPFactoryBaseClass : NSObject <DPFactoryProtocol>
@end
// 创建产品A类,可以遵守产品协议,也可以继承产品基类 需要实现产品协议中的方法
@interface DPFactoryA : NSObject <DPFactoryProtocol>
@end
#import "DPFactoryA.h"
#import "DPFactoryProductA.h"
@implementation DPFactoryA
- (DPFactoryProductBaseClass *)factoryCreateProduct{
DPFactoryProductA * product = [[DPFactoryProductA alloc] init];
return product;
}
@end
#import <Foundation/Foundation.h>
#import "DPFactoryProtocol.h"
// 创建产品B类,可以遵守产品协议,也可以继承产品基类 需要实现产品协议中的方法
@interface DPFactoryB : NSObject<DPFactoryProtocol>
@end
#import "DPFactoryB.h"
#import "DPFactoryProductB.h"
@implementation DPFactoryB
- (DPFactoryProductBaseClass *)factoryCreateProduct{
DPFactoryProductB * product = [[DPFactoryProductB alloc] init];
return product;
}
@end
#import <Foundation/Foundation.h>
//创建工厂协议
@protocol DPFactoryProductProtocol <NSObject>
@optional
- (void)productFunction;
@end
//创建工厂基类
@interface DPFactoryProductBaseClass : NSObject <DPFactoryProductProtocol>
@end
#import <Foundation/Foundation.h>
#import "DPFactoryProductProtocol.h"
//创建生产产品A的工厂, 它必须继承工厂协议或者继承工厂基类
@interface DPFactoryProductA : DPFactoryProductBaseClass
@end
#import "DPFactoryProductA.h"
@implementation DPFactoryProductA
- (void)productFunction{
NSLog(@"我是工厂模式生产出来的A产品");
}
@end
#import <Foundation/Foundation.h>
#import "DPFactoryProductProtocol.h"
//创建生产产品B的工厂, 它必须继承工厂协议或者继承工厂基类
@interface DPFactoryProductB :DPFactoryProductBaseClass
@end
#import "DPFactoryProductB.h"
@implementation DPFactoryProductB
- (void)productFunction{
NSLog(@"我是工厂模式生产出来的B产品");
}
@end
typedef NS_ENUM(NSInteger, ProductType) {
ProductTypeA,
ProductTypeB
};
//供客户使用的类
@interface DPFactoryUseForClent : NSObject
//根据客户传入的产品类型生产出相应的产品
- (DPFactoryProductBaseClass *)createProductWithProductType:(ProductType) productType;
@end
@implementation DPFactoryUseForClent
- (DPFactoryProductBaseClass *)createProductWithProductType:(ProductType) productType{
DPFactoryProductBaseClass * product = nil;
switch (productType) {
case ProductTypeA:
{
DPFactoryA * factory = [[DPFactoryA alloc] init];
product = [factory factoryCreateProduct];
}
break;
case ProductTypeB:
{
DPFactoryB * factory = [[DPFactoryB alloc] init];
product = [factory factoryCreateProduct];
}
break;
default:
break;
}
return product;
}
@end
//客户端使用
DPFactoryUseForClent * clent = [[DPFactoryUseForClent alloc]init];
DPFactoryProductBaseClass * productA = [clent createProductWithProductType:ProductTypeA];
[productA productFunction];
DPFactoryProductBaseClass * productB = [clent createProductWithProductType:ProductTypeB];
[productB productFunction];
2017-01-04 14:43:00.303 DesignPatterns[40735:3389989] 我是工厂模式生产出来的A产品
2017-01-04 14:43:00.304 DesignPatterns[40735:3389989] 我是工厂模式生产出来的B产品
抽象工厂模式
抽象工厂模式顾名思义是对工厂模式中工厂的进一步抽象,但他又不同于多工厂工厂模式,它提供一个创建一系列的相互依赖的接口,而无需指定他们具体的类。一般抽象工厂都是生成一组相互依赖的产品的,往往是多个。下面我们来看看抽象工厂模式:
例子(oc版):
@protocol DPCreateNotebookComputerProtocol <NSObject>
@optional
- (void)createNotebookComputer;
@end
@interface DPCreateNotebookComputerBaseClass : NSObject<DPCreateNotebookComputerProtocol>
@end
#import <Foundation/Foundation.h>
#import "DPCreateNotebookComputerProtocol.h"
@interface DPCreateHuaWeiNotebookComputer : DPCreateNotebookComputerBaseClass
@end
#import "DPCreateHuaWeiNotebookComputer.h"
@implementation DPCreateHuaWeiNotebookComputer
- (void)createNotebookComputer{
NSLog(@"我是抽象工厂模式生产的华为笔记本电脑");
}
@end
#import <Foundation/Foundation.h>
#import "DPCreateNotebookComputerProtocol.h"
@interface DPIphoneNotebookComputer : DPCreateNotebookComputerBaseClass
@end
#import "DPIphoneNotebookComputer.h"
@implementation DPIphoneNotebookComputer
- (void)createNotebookComputer{
NSLog(@"我是抽象工厂模式生产的苹果笔记本电脑");
}
@end
#import <Foundation/Foundation.h>
@protocol DPCreatePhoneProtocol <NSObject>
@optional
- (void)createPhone;
@end
@interface DPCreatePhoneBase : NSObject<DPCreatePhoneProtocol>
@end
#import <Foundation/Foundation.h>
#import "DPCreatePhoneProtocol.h"
@interface DPCreateHuaWeiPhone :DPCreatePhoneBase
@end
#import "DPCreateHuaWeiPhone.h"
@implementation DPCreateHuaWeiPhone
- (void)createPhone{
NSLog(@"我是抽象工厂模式生产的华为手机");
}
@end
#import <Foundation/Foundation.h>
#import "DPCreatePhoneProtocol.h"
@interface DPCreateiPhone6s : DPCreatePhoneBase
@end
#import "DPCreateiPhone6s.h"
@implementation DPCreateiPhone6s
- (void)createPhone{
NSLog(@"我是抽象工厂模式生产的苹果6s手机");
}
@end
#import <Foundation/Foundation.h>
#import "DPCreateNotebookComputerProtocol.h"
#import "DPCreatePhoneProtocol.h"
@protocol DPAbstractFactoryProtocol <NSObject>
@optional
- (DPCreateNotebookComputerBaseClass *)factoryCreateNotebookComputer;
- (DPCreatePhoneBase *)factoryCreatePhone;
@end
@interface DPFactoryBase : NSObject<DPAbstractFactoryProtocol>
@end
#import <Foundation/Foundation.h>
#import "DPFactoryProtocol.h"
@interface DPHuaWeiFactory : DPFactoryBase
@end
#import "DPHuaWeiFactory.h"
#import "DPCreateHuaWeiNotebookComputer.h"
#import "DPCreateHuaWeiPhone.h"
@implementation DPHuaWeiFactory
- (id<DPCreateNotebookComputerProtocol>)factoryCreateNotebookComputer{
DPCreateHuaWeiNotebookComputer * computer = [[DPCreateHuaWeiNotebookComputer alloc] init];
return computer;
}
- (id<DPCreatePhoneProtocol>)factoryCreatePhone{
DPCreateHuaWeiPhone * phone = [[DPCreateHuaWeiPhone alloc] init];
return phone;
}
@end
#import <Foundation/Foundation.h>
#import "DPFactoryProtocol.h"
@interface DPIPhoneFactory : DPFactoryBase
@end
#import "DPIPhoneFactory.h"
#import "DPIphoneNotebookComputer.h"
#import "DPCreateiPhone6s.h"
@implementation DPIPhoneFactory
- (id<DPCreateNotebookComputerProtocol>)factoryCreateNotebookComputer{
DPIphoneNotebookComputer * computer = [[DPIphoneNotebookComputer alloc] init];
return computer;
}
- (id<DPCreatePhoneProtocol>)factoryCreatePhone{
DPCreateiPhone6s * phone = [[DPCreateiPhone6s alloc] init];
return phone;
}
@end
#import <Foundation/Foundation.h>
#import "DPIphoneNotebookComputer.h"
#import "DPCreateiPhone6s.h"
#import "DPCreateHuaWeiNotebookComputer.h"
#import "DPCreateHuaWeiPhone.h"
#import "DPFactoryProtocol.h"
#import "DPIPhoneFactory.h"
#import "DPHuaWeiFactory.h"
typedef NS_ENUM(NSInteger, FactoryType) {
HuaWei,
iPhone
};
@interface DPAbstractFactoryUseForClent : NSObject
- (DPFactoryBase *)clentCreateFactoryWith:(FactoryType) FactoryType;
@end
#import "DPAbstractFactoryUseForClent.h"
@implementation DPAbstractFactoryUseForClent
- (DPFactoryBase *)clentCreateFactoryWith:(FactoryType) FactoryType{
DPFactoryBase * factory = nil;
switch (FactoryType) {
case HuaWei:
{
factory = [[DPHuaWeiFactory alloc] init];
}
break;
case iPhone:
{
factory = [[DPIPhoneFactory alloc] init];
}
break;
default:
break;
}
return factory;
}
@end
//客户端使用
DPAbstractFactoryUseForClent * clent = [[DPAbstractFactoryUseForClent alloc] init];
DPFactoryBase * factoryHuaWei = [clent clentCreateFactoryWith:HuaWei];
DPCreateNotebookComputerBaseClass * huaWeiNoteBook = [factoryHuaWei factoryCreateNotebookComputer];
[huaWeiNoteBook createNotebookComputer];
DPCreatePhoneBase * huaWeiPhone = [factoryHuaWei factoryCreatePhone];
[huaWeiPhone createPhone];
DPFactoryBase * factoryiPhone = [clent clentCreateFactoryWith:iPhone];
DPCreateNotebookComputerBaseClass * iPhoneNoteBook = [factoryiPhone factoryCreateNotebookComputer];
[iPhoneNoteBook createNotebookComputer];
DPCreatePhoneBase * iPhone = [factoryiPhone factoryCreatePhone];
[iPhone createPhone];
2017-01-04 16:37:51.545 DesignPatterns[41125:3455076] 我是抽象工厂模式生产的华为笔记本电脑
2017-01-04 16:37:51.546 DesignPatterns[41125:3455076] 我是抽象工厂模式生产的华为手机
2017-01-04 16:37:51.546 DesignPatterns[41125:3455076] 我是抽象工厂模式生产的苹果笔记本电脑
2017-01-04 16:37:51.546 DesignPatterns[41125:3455076] 我是抽象工厂模式生产的苹果6s手机
类族
类簇和工厂模式很类似,它通过在基类中提供工厂方法,隐藏具体的子类实现。例如Cocoa中的类方法
NSNumber * a = [NSNumber numberWithBool:YES];
NSNumber * b = [NSNumber numberWithInteger:123];
NSLog(@"%@",NSStringFromClass([a class])); //__NSCFBoolean
NSLog(@"%@",NSStringFromClass([b class])); //__NSCFNumber
可以看到实际上NSNumber的Runtime类并不是NSNumber,NSNumber只是定义了一个高度抽象的基类,它既是产品类,又是工厂类。通过提供numberWith***一些列方法,隐藏了具体的子类实现。类似的还有[UIButton buttonWithType:].Cocoa中,使用类簇的设计模式有NSDictionary,NSData,NSString等。