读《大话设计模式》一

前言

对设计模式的理解,不够透彻,有时去找资料,总是零零散散,不成系统,故将《大话设计模式》中的干货整理下,方便需要使用时可以参考使用。

设计模式六大原则

单一职责原则

  • 定义:就一个类而言,应该仅有一个引起它变化的原因。通俗的说,即一个类只负责一项职责。
    问题由来:类T负责两个不同的职责:职责P1,职责P2。当由于职责P1需求发生改变而需要修改类T时,有可能会导致原本运行正常的职责P2功能发生故障。
  • 解决方案:遵循单一职责原则。分别建立两个类T1、T2,使T1完成职责P1功能,T2完成职责P2功能。这样,当修改类T1时,不会使职责P2发生故障风险;同理,当修改T2时,也不会使职责P1发生故障风险。
  • 最佳实践:
    • 可以降低类的复杂度,一个类只负责一项职责,其逻辑肯定要比负责多项职责简单的多;
    • 提高类的可读性,提高系统的可维护性;
    • 降低需求变更引起的风险。

里氏替换原则

  • 定义:子类型必须能够替换掉它们的父类型。
  • 问题由来:有一功能P1,由类A完成。现需要将功能P1进行扩展,扩展后的功能为P,其中P由原有功能P1与新功能P2组成。新功能P由类A的子类B来完成,则子类B在完成新功能P2的同时,有可能会导致原有功能P1发生故障。
  • 解决方案:当使用继承时,遵循里氏替换原则。类B继承类A时,除添加新的方法完成新增功能P2外,尽量不要重写父类A的方法,也尽量不要重载父类A的方法。

依赖倒转原则

  • 定义:A.高层模块不应该依赖底层模块。两者都应该依赖抽象。B.抽象不应该依赖细节。细节应该依赖抽象。通俗理解:针对接口编程,不要针对实现编程。
  • 问题由来:类A直接依赖类B,假如要将类A改为依赖类C,则必须通过修改类A的代码来达成。这种场景下,类A一般是高层模块,负责复杂的业务逻辑;类B和类C是低层模块,负责基本的原子操作;假如修改类A,会给程序带来不必要的风险。
  • 解决方案:将类A修改为依赖接口I,类B和类C各自实现接口I,类A通过接口I间接与类B或者类C发生联系,则会大大降低修改类A的几率。
  • 最佳实践:
    • 低层模块尽量都要有抽象类或接口,或者抽象类或接口两者都具备。
    • 变量的声明类型尽量是抽象类或接口。
    • 使用继承时遵循里氏替换原则。

接口隔离原则

  • 定义:一个类对另一个类的依赖,应该建立在最小的接口上。
  • 问题由来:类A通过接口I依赖类B,类C通过接口I依赖类D,如果接口I对于类A和类B来说不是最小接口,则类B和类D必须去实现他们不需要的方法。
  • 解决方案:将臃肿的接口I拆分为独立的几个接口,类A和类C分别与他们需要的接口建立依赖关系。也就是采用接口隔离原则。


    未遵循接口隔离原则的设计

    遵循接口隔离原则的设计
  • 最佳实践:
    • 接口尽量小,但是要有限度。对接口进行细化可以提高程序设计灵活性是不挣的事实,但是如果过小,则会造成接口数量过多,使设计复杂化。所以一定要适度;
    • 为依赖接口的类定制服务,只暴露给调用的类它需要的方法,它不需要的方法则隐藏起来。只有专注地为一个模块提供定制服务,才能建立最小的依赖关系;
    • 提高内聚,减少对外交互。使接口用最少的方法去完成最多的事情;
    • 适度使用,接口设计的过大或过小都不好。

迪米特法则

  • 定义:又叫最少知道原则,如果两个类不必彼此直接通信,那么这两个类就不应当发生直接的相互作用。如果其中一个类需要调用另一个类的某一个方法的话,可以通过第三者转发这个调用。
    一个对象应该对其他对象保持最少的了解。
  • 问题由来:类与类之间的关系越密切,耦合度越大,当一个类发生改变时,对另一个类的影响也越大。
  • 最佳实践:尽量降低类与类之间的耦合。可以通过第三者来进行通信。

开放-封闭原则

  • 定义:软件实体(类、模块、函数等等)应该可以扩展,但是不可修改。
  • 问题由来:在软件的生命周期内,因为变化、升级和维护等原因需要对软件原有代码进行修改时,可能会给旧代码中引入错误,也可能会使我们不得不对整个功能进行重构,并且需要原有代码经过重新测试。
  • 解决方案:当软件需要变化时,尽量通过扩展软件实体的行为来实现变化,而不是通过修改已有的代码来实现变化。

六大原则总结

用抽象构建框架,用实现扩展细节。

  • 单一职责原则告诉我们实现类要职责单一;
  • 里氏替换原则告诉我们不要破坏继承体系;
  • 依赖倒置原则告诉我们要面向接口编程;
  • 接口隔离原则告诉我们在设计接口的时候要精简单一;
  • 迪米特法则告诉我们要降低耦合。
  • 而开闭原则是总纲,它告诉我们要对扩展开放,对修改关闭。

设计模式六大原则

UML基础知识

UML类图图示

类与类之间的关系

  • 泛化:是一种继承关系,表示一般与特殊的关系,存在于父类与子类、父接口与子接口之间,表示子类如何特
    化父类的所有特征和行为,比如动物和鸟之间的关系;
  • 实现:一种类与接口的关系,表示类对接口所有特征和行为的实现,比如大雁与接口飞翔的关系;
  • 组合:是一种强的‘拥有’关系,体现了严格的整体和部分的关系,部分和整体的生命周期一样,比如鸟与翅膀的关系;
  • 聚合:是一种弱的‘拥有’关系,体现的是A对象可以包含B对象,但B对象不是A对象的一部分,比如雁群和大雁的关系;
  • 关联:描述了类与类之间的结构化关系,具有方向、名字、角色和多重性等信息,是一种拥有的关
    系,它使一个类知道另一个类的属性和方法,比如企鹅与气候的关系,人与住址的关系;
  • 依赖:是一种使用关系,特定事物的改变有可能会影响到使用该事物的其他事物,表示一个事
    物使用另一个事物时使用依赖关系。大多数情况下,依赖关系体现在某个类的方法使用另一个类的对象作为参数。
    1、将一个类的对象作为另一个类中方法的参数
    2、在一个类的方法中将另一个类的对象作为其局部变量
    3、在一个类的方法中调用另一个类的静态方法。

各种关系的强弱顺序:
泛化 = 实现 > 组合 > 聚合 > 关联 > 依赖

常用的23中设计模式

创建型模式

简单工厂模式

模式动机

考虑一个简单的软件应用场景,一个计算器有不同的按钮(如+、-、*、÷), 这些按钮都源自同一个基类,不过在继承基类后不同的子类修改了部分属性从而使得它们可以完成不同的功能,如果我们希望在使用这些按钮时,不需要知道这些具体按钮类的名字,只需要知道表示该按钮类的一个参数,并提供一个调用方便的方法,把该参数传入方法即可返回一个相应的按钮对象,此时,就可以使用简单工厂模式。

模式定义

简单工厂模式(Simple Factory Pattern):它属于类创建型模式。在简单工厂模式中,可以根据参数的不同返回不同类的实例。简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。

模式结构

简单工厂模式包含如下角色:

  • HCDCalcuteFactory:工厂角色
    工厂角色负责实现创建所有实例的内部逻辑
  • HCDCalculate:抽象产品角色
    抽象产品角色是所创建的所有对象的父类,负责描述所有实例所共有的公共接口
  • HCDCalculateAdd:具体产品角色
    具体产品角色是创建目标,所有创建的对象都充当这个角色的某个具体类的实例。
简单工厂模式类图
时序图
简单工厂模式时序图
源码
//HCDCalculateProtocol.h
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

typedef NS_ENUM(NSInteger, HCDCalculateType) {
    HCDCalculateTypeAdd = 0,   //加
    HCDCalculateTypeMinus,     //减
    HCDCalculateTypeMultipy,   //乘
    HCDCalculateTypeDivide     //除
};

@protocol HCDCalculateProtocol <NSObject>

@optional
-(CGFloat)calculate;

@end
//HCDCalculate.h
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import "HCDCalculateProtocol.h"

@interface HCDCalculate : NSObject <HCDCalculateProtocol>

@property(nonatomic, assign) CGFloat numberA;
@property(nonatomic, assign) CGFloat numberB;

@end
//HCDCalcuteFactory.h
#import <Foundation/Foundation.h>
#import "HCDCalculate.h"

@interface HCDCalcuteFactory : NSObject

+(HCDCalculate *)createCalcute:(NSString *)calculatetype;

@end

//HCDCalcuteFactory.m
#import "HCDCalcuteFactory.h"
#import "HCDCalculateAdd.h"
#import "HCDCalculateDivide.h"
#import "HCDCalculateMinus.h"
#import "HCDCalcuteMultiply.h"

@implementation HCDCalcuteFactory

+(HCDCalculate *)createCalcute:(NSString *)calculatetype {
    
    NSArray *calculateArray = @[@"+",@"-",@"*",@"/"];
    
    if (![calculateArray containsObject:calculatetype]) {
        return nil;
    }
    HCDCalculateType calType = [calculateArray indexOfObject:calculatetype];
    
    
    switch (calType) {
        case HCDCalculateTypeAdd:
            return [[HCDCalculateAdd alloc]init];
            break;
        case HCDCalculateTypeMinus:
            return [[HCDCalculateMinus alloc]init];
            break;
        case HCDCalculateTypeMultipy:
            return [[HCDCalcuteMultiply alloc]init];
        case HCDCalculateTypeDivide:
            return [[HCDCalculateDivide alloc]init];
    }
}
@end
//HCDCalculateAdd.m
#import "HCDCalculateAdd.h"

@implementation HCDCalculateAdd

-(CGFloat)calculate{
    return self.numberA + self.numberB;
}
@end

//HCDCalculateMinus.m
#import "HCDCalculateMinus.h"

@implementation HCDCalculateMinus

-(CGFloat)calculate{
    return self.numberA - self.numberB;
}

@end

//HCDCalcuteMultiply
#import "HCDCalcuteMultiply.h"

@implementation HCDCalcuteMultiply

-(CGFloat)calculate{
    return self.numberA * self.numberB;
}
@end

//HCDCalculateDivide.m
#import "HCDCalculateDivide.h"

@implementation HCDCalculateDivide

- (CGFloat)calculate{
    if (self.numberB == 0) {
        NSLog(@"dividend is can not be zero!");
        return 0;
    }
    return self.numberA/self.numberB;
}

@end

工厂方法模式

模式动机

现在对该系统进行修改,不再设计一个运算工厂类来统一负责所有产品的创建,而是将具体运算的创建过程交给专门的工厂子类去完成,我们先定义一个抽象的运算工厂类,再定义具体的工厂类来生成加法运算、减法运算、乘法运算等,它们实现在抽象按钮工厂类中定义的方法。这种抽象化的结果使这种结构可以在不修改具体工厂类的情况下引进新的产品,如果出现新的按钮类型,只需要为这种新类型的按钮创建一个具体的工厂类就可以获得该新运算的实例,这一特点无疑使得工厂方法模式具有超越简单工厂模式的优越性,更加符合“开闭原则”。

模式定义

工厂方法模式,它属于类创建型模式。在工厂方法模式中,工厂父类负责定义创建产品对象的公共接口,而工厂子类则负责生成具体的产品对象,这样做的目的是将产品类的实例化操作延迟到工厂子类中完成,即通过工厂子类来确定究竟应该实例化哪一个具体产品类。

模式结构

工厂方法模式包含如下角色:

  • HCDCalculate:抽象产品
  • HCDCalculateAdd:具体产品
  • HCDfactory:抽象工厂
  • HCDfactoryAdd:具体工厂


    工厂方法模式类图
时序图
工厂方法模式时序图
源码
//HCDfactory.h

#import <Foundation/Foundation.h>
#import "HCDCalculate.h"

@interface HCDfactory : NSObject

-(HCDCalculate *)createFactory;

@end

//HCDfactory.m
#import "HCDfactory.h"

@implementation HCDfactory

-(HCDCalculate *)createFactory {
    return nil;
}

@end

//HCDfactoryAdd.m
@implementation HCDfactoryAdd

-(HCDCalculate *)createFactory {
    return [[HCDCalculateAdd alloc]init];
}
@end

//HCDfactoryMinus.m
@implementation HCDfactoryMinus

-(HCDCalculate *)createFactory {
    return [[HCDCalculateMinus alloc]init];
}
@end

//HCDfactoryMultiply.m
@implementation HCDfactoryMultiply

-(HCDCalculate *)createFactory {
    return [[HCDCalcuteMultiply alloc]init];
}
@end

//HCDfactoryDivide.m
@implementation HCDfactoryDivide

-(HCDCalculate *)createFactory {
    return [[HCDCalculateDivide alloc]init];
}
@end
//HCDCalculate.h
@interface HCDCalculate : NSObject <HCDCalculateProtocol>

@property(nonatomic, assign) CGFloat numberA;
@property(nonatomic, assign) CGFloat numberB;

@end

//HCDCalculateAdd.m
@implementation HCDCalculateAdd

-(CGFloat)calculate{
    return self.numberA + self.numberB;
}
@end

//HCDCalculateMinus.m
@implementation HCDCalculateMinus

-(CGFloat)calculate{
    return self.numberA - self.numberB;
}

@end

//HCDCalcuteMultiply.m
@implementation HCDCalcuteMultiply

-(CGFloat)calculate{
    return self.numberA * self.numberB;
}
@end

//HCDCalculateDivide.m
@implementation HCDCalculateDivide

- (CGFloat)calculate{
    if (self.numberB == 0) {
        NSLog(@"dividend is can not be zero!");
        return 0;
    }
    return self.numberA/self.numberB;
}

@end

//HCDCalculateProtocol.h
typedef NS_ENUM(NSInteger, HCDCalculateType) {
    HCDCalculateTypeAdd = 0,   //加
    HCDCalculateTypeMinus,     //减
    HCDCalculateTypeMultipy,   //乘
    HCDCalculateTypeDivide     //除
};

@protocol HCDCalculateProtocol <NSObject>

@optional
-(CGFloat)calculate;

@end
//使用示例
    HCDfactory *addFactory = [[HCDfactoryAdd alloc]init];
    HCDCalculate *addCalculate = [addFactory createFactory];
    addCalculate.numberA = 10;
    addCalculate.numberB = 15;
    NSLog(@"结果是%f\n",[addCalculate calculate]);
    
    HCDfactory *minusFactory = [[HCDfactoryMinus alloc]init];
    HCDCalculate *minusCalculate = [minusFactory createFactory];
    minusCalculate.numberA = 10;
    minusCalculate.numberB = 15;
    NSLog(@"结果是%f\n",[minusCalculate calculate]);
    
    HCDfactory *multiplyFactory = [[HCDfactoryMultiply alloc]init];
    HCDCalculate *multiplyCalculate = [multiplyFactory createFactory];
    multiplyCalculate.numberA = 10;
    multiplyCalculate.numberB = 15;
    NSLog(@"结果是%f\n",[multiplyCalculate calculate]);
    
    HCDfactory *divideFactory = [[HCDfactoryDivide alloc]init];
    HCDCalculate *divideCalculate = [divideFactory createFactory];
    divideCalculate.numberA = 10;
    divideCalculate.numberB = 15;
    NSLog(@"结果是%f\n",[divideCalculate calculate]);
    

抽象工厂模式

模式动机
  • 在工厂方法模式中具体工厂负责生产具体的产品,每一个具体工厂对应一种具体产品,工厂方法也具有唯一性,一般情况下,一个具体工厂中只有一个工厂-方法或者一组重载的工厂方法。但是有时候我们需要一个工厂可以提供多个产品对象,而不是单一的产品对象。
  • 当系统所提供的工厂所需生产的具体产品并不是一个简单的对象,而是多个位于不同产品等级结构中属于不同类型的具体产品时需要使用抽象工厂模式。
模式定义

抽象工厂模式:提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。属于对象创建型模式。

模式结构

抽象工厂模式包含如下角色:

  • HCDFactory:抽象工厂
  • HCDSqlserverFactory:具体工厂
  • HCDDepartment:抽象产品
  • HCDSqlserverDepartment:具体产品
抽象工厂模式类图
时序图
抽象工厂模式时序图
源码
//HCDFactory.h
@protocol HCDFactory <NSObject>

-(id<HCDUser>)createUser;
-(id<HCDDepartment>)createDepartment;

@end

//HCDSqlserverFactory.m
@implementation HCDSqlserverFactory

-(id<HCDUser>)createUser{
    return [[HCDSqlserverUser alloc]init];
}

-(id<HCDDepartment>)createDepartment{
    return [[HCDSqlserverDepartment alloc]init];
}

@end

//HCDAccessFactory.m
-(id<HCDUser>)createUser{
    return [[HCDAccessUser alloc]init];
}

-(id<HCDDepartment>)createDepartment{
    return [[HCDAccessDepartment alloc]init];
}

@end 
//HCDDepartment.h
@protocol HCDDepartment <NSObject>

-(void)insertDepartment:(SQLDepartment *)department;

-(SQLDepartment *)getDepartment;

@end

//HCDSqlserverDepartment.m
@implementation HCDSqlserverDepartment

-(SQLDepartment *)getDepartment{
    NSLog(@"新建一个Sqlserver的SQLDepartment对象");
    return [[SQLDepartment alloc]init];
}

-(void)insertDepartment:(SQLDepartment *)department{
    NSLog(@"插入一个Sqlserver的SQLDepartment对象");
}

@end

//HCDAccessDepartment.m
@implementation HCDAccessDepartment

-(SQLDepartment *)getDepartment{
    NSLog(@"新建一个Access的SQLDepartment对象");
    return [[SQLDepartment alloc]init];
}

-(void)insertDepartment:(SQLDepartment *)department{
    NSLog(@"插入一个Access的SQLDepartment对象");
}

@end
//HCDUser.h
@protocol HCDUser <NSObject>

-(void)insertUser:(SQLUser *)user;

-(SQLUser *)getUser;

@end

//HCDSqlserverUser.m
@implementation HCDSqlserverUser

-(SQLUser *)getUser{
    NSLog(@"新建一个Sqlserver的SQLUser对象");
    return [[SQLUser alloc]init];
}

-(void)insertUser:(SQLUser *)user{
     NSLog(@"插入一个Sqlserver的SQLUser对象");
}

@end

//HCDAccessUser.m
@implementation HCDAccessUser

-(SQLUser *)getUser{
    NSLog(@"新建一个Access的SQLUser对象");
    return [[SQLUser alloc]init];
}

-(void)insertUser:(SQLUser *)user{
    NSLog(@"插入一个Access的SQLUser对象");
}

@end
//使用示例
    id<HCDFactory> factory0 = [[HCDSqlserverFactory alloc]init];
    id<HCDDepartment> department0 = [factory0 createDepartment];
    [department0 insertDepartment:[[SQLDepartment alloc]init]];
    [department0 getDepartment];
    
    id<HCDUser> user0 = [factory0 createUser];
    [user0 insertUser:[[SQLUser alloc] init]];
    [user0 getUser];
    
    id<HCDFactory> factory1 = [[HCDAccessFactory alloc]init];
    id<HCDDepartment> department1 = [factory1 createDepartment];
    [department1 insertDepartment:[[SQLDepartment alloc]init]];
    [department1 getDepartment];
    
    id<HCDUser> user1 = [factory1 createUser];
    [user1 insertUser:[[SQLUser alloc] init]];
    [user1 getUser];

建造者模式

模式动机

无论是在现实世界中还是在软件系统中,都存在一些复杂的对象,它们拥有多个组成部分,如汽车,它包括车轮、方向盘、发送机等各种部件。而对于大多数用户而言,无须知道这些部件的装配细节,也几乎不会使用单独某个部件,而是使用一辆完整的汽车,可以通过建造者模式对其进行设计与描述,建造者模式可以将部件和其组装过程分开,一步一步创建一个复杂的对象。用户只需要指定复杂对象的类型就可以得到该对象,而无须知道其内部的具体构造细节。

模式定义

造者模式:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

模式结构

建造者模式包含如下角色:

  • Builder:抽象建造者
  • ConcreteBuilder:具体建造者
  • Director:指挥者
  • Product:产品角色


    建造者模式类图
时序图
建造者模式时序图
源码
//HCDPersonBuilderDirector.h
@class HCDPresionBuilder;
@interface HCDPersonBuilderDirector : NSObject

- (instancetype)initWithBuilder:(HCDPresionBuilder *)builder;

- (void)buildPerson; 

@end

//HCDPersonBuilderDirector.m
@interface HCDPersonBuilderDirector ()

@property (nonatomic, strong) HCDPresionBuilder *builder;

@end

@implementation HCDPersonBuilderDirector

- (instancetype)initWithBuilder:(HCDPresionBuilder *)builder {
    self = [super init];
    if (self) {
        self.builder = builder;
    }
    return self;
}

- (void)buildPerson {
    [self.builder buildHead];
    [self.builder buildBody];
    [self.builder buildArmLeft];
    [self.builder buildArmRight];
    [self.builder buildLegLeft];
    [self.builder buildLegRight];
    [self.builder getResult];
}

@end
//HCDPresionBuilderProtocol.h
ypedef  NS_ENUM(NSUInteger,HCDBuildOption){
    HCDBuildOptionFat = 0,  //胖的人
    HCDBuildOptionThin      //瘦的人
};

@protocol HCDPresionBuilderProtocol <NSObject>

- (void)buildHead;
- (void)buildBody;
- (void)buildArmLeft;
- (void)buildArmRight;
- (void)buildLegLeft;
- (void)buildLegRight;

- (HCDProduct *)getResult;

@end 

//HCDPresionBuilder.h
@interface HCDPresionBuilder : NSObject<HCDPresionBuilderProtocol>

@end

//HCDPersonFatBuilder.m
@interface HCDPersonFatBuilder()

@property (nonatomic, strong) HCDProduct *product;

@end

@implementation HCDPersonFatBuilder

-(instancetype)init{
    self = [super init];
    if (self) {
        _product = [[HCDProduct alloc] init];
    }
    return self;
} 

- (void)buildHead {
    NSLog(@"建造胖子的头部");
    [self.product.header work];
}

- (void)buildBody {
    NSLog(@"建造胖子的身体");
    [self.product.body work];
}

- (void)buildArmLeft {
    NSLog(@"建造胖子的左手");
    [self.product.arm work];
}

- (void)buildArmRight {
    NSLog(@"建造胖子的右手");
    [self.product.arm work];
}

- (void)buildLegLeft {
    NSLog(@"建造胖子的左脚");
    [self.product.leg work];
}

- (void)buildLegRight {
    NSLog(@"建造胖子的右脚");
    [self.product.leg work];
}

- (HCDProduct *)getResult {
    return self.product;
}

@end

//HCDPersonThinBuilder.m
@interface HCDPersonThinBuilder ()

@property (nonatomic, strong) HCDProduct *product;

@end

@implementation HCDPersonThinBuilder

-(instancetype)init{
    self = [super init];
    if (self) {
        _product = [[HCDProduct alloc] init];
    }
    return self;
}
 
- (void)buildHead {
    NSLog(@"建造瘦子的头部");
    [self.product.header work];
}

- (void)buildBody {
    NSLog(@"建造瘦子的身体");
    [self.product.body work];
}

- (void)buildArmLeft {
    NSLog(@"建造瘦子的左手");
    [self.product.arm work];
}

- (void)buildArmRight {
    NSLog(@"建造瘦子的右手");
    [self.product.arm work];
}

- (void)buildLegLeft {
    NSLog(@"建造瘦子的左脚");
    [self.product.leg work];
}

- (void)buildLegRight {
    NSLog(@"建造瘦子的右脚");
    [self.product.leg work];
}

- (HCDProduct *)getResult {
    return self.product;
}

@end
//使用示例
- (IBAction)buildFat:(id)sender {
    HCDPersonFatBuilder *builder = [[HCDPersonFatBuilder alloc]init];
    HCDPersonBuilderDirector *director = [[HCDPersonBuilderDirector alloc] initWithBuilder:builder];
    [director buildPerson];
}

- (IBAction)buildThin:(id)sender {
    HCDPersonThinBuilder *builder = [[HCDPersonThinBuilder alloc]init];
    HCDPersonBuilderDirector *director = [[HCDPersonBuilderDirector alloc] initWithBuilder:builder];
    [director buildPerson];
}

单例模式

模式动机

对于系统中的某些类来说,只有一个实例很重要,例如,一个系统中可以存在多个打印任务,但是只能有一个正在工作的任务;一个系统只能有一个窗口管理器或文件系统;一个系统只能有一个计时工具或ID(序号)生成器。
如何保证一个类只有一个实例并且这个实例易于被访问呢?定义一个全局变量可以确保对象随时都可以被访问,但不能防止我们实例化多个对象。
一个更好的解决办法是让类自身负责保存它的唯一实例。这个类可以保证没有其他实例被创建,并且它可以提供一个访问该实例的方法。这就是单例模式的模式动机

模式定义

单例模式:单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,它提供全局访问的方法。

模式结构
单例模式类图
时序图
单例模式时序图
源码
+(instancetype)sharedInstance{
    static HCDSingleton *singleton = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        singleton = [[HCDSingleton alloc]init];
    });
    return singleton;
}

原型模式

模式动机
  • 将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝自己来实现创建过程。
  • 通过克隆方法所创建的对象是全新的对象,它们在内存中拥有新的地址,通常对克隆所产生的对象进行修改对原型对象不会造成任何影响,每一个克隆对象都是相互独立的。通过不同的方式修改可以得到一系列相似但不完全相同的对象。
模式定义

使用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。原型模式是一种对象创建型模式。
备注:复制分浅复制和深复制

  • 浅复制:被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用都仍然指向原来的对象;
  • 深复制:把引用对象的变量指向复制过的新对象,而不是原有的被引用的对象。

iOS深拷贝和浅拷贝

结构式模式

组合模式

模式动机
  • 对于树形结构,当容器对象的某一个方法被调用时,将遍历整个树形结构,寻找也包含这个方法的成员对象(可以是容器对象,也可以是叶子对象,如子文件夹和文件)并调用执行。(递归调用)
  • 由于容器对象和叶子对象在功能上的区别,在使用这些对象的客户端代码中必须有区别地对待容器对象和叶子对象,而实际上大多数情况下客户端希望一致地处理它们,因为对于这些对象的区别对待将会使得程序非常复杂。
    组合模式描述了如何将容器对象和叶子对象进行递归组合,使得用户在使用时无须对它们进行区分,可以一致地对待容器对象和叶子对象,这就是组合模式的模式动机。
模式定义

将对象组合成树形结构以表示‘部分-整体’的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。

模式结构

模板方法模式包含如下角色:

  • Component: 对象声明接口
  • Leaf: 叶节点对象
  • Composite: 枝节点行为


    组合模式类图
时序图

源码
    //使用示例
    HCDConcreteCompany *root = [[HCDConcreteCompany alloc] initWithName:@"总公司"];
    [root add:[[HCDHRDepartment alloc] initWithName:@"总公司人力资源部"]];
    [root add:[[HCDFinanceDepartment alloc] initWithName:@"总公司财务部"]];
    
    HCDConcreteCompany *comp = [[HCDConcreteCompany alloc] initWithName:@"上海华东分公司"];
    [comp add:[[HCDHRDepartment alloc] initWithName:@"上海华东分公司人力资源部"]];
    [comp add:[[HCDFinanceDepartment alloc] initWithName:@"上海华东分公司财务部"]];
    [root add:comp];
    
    HCDConcreteCompany *office = [[HCDConcreteCompany alloc] initWithName:@"杭州办事处"];
    [office add:[[HCDHRDepartment alloc] initWithName:@"杭州办事处人力资源部"]];
    [office add:[[HCDFinanceDepartment alloc] initWithName:@"杭州办事处财务部"]];
    NSLog(@"\n");
    [comp add:office];
    NSLog(@"结构图:--------------------------");
    [root display:1];
    NSLog(@"\n");
    NSLog(@"职责:---------------------------");
    [root lineofDuty];
//HCDCompany.h
@interface HCDCompany : NSObject

@property (nonatomic,copy) NSString *name;

- (instancetype)initWithName:(NSString *)name;

-(void)add:(HCDCompany *)company;

-(void)remove:(HCDCompany *)company;

-(void)display:(NSInteger)depth;

-(void)lineofDuty;

@end
//HCDConcreteCompany.h
@interface HCDConcreteCompany : HCDCompany

@end

//HCDConcreteCompany.m
@interface HCDConcreteCompany ()

@property (nonatomic, strong) NSMutableArray *childList;

@end

@implementation HCDConcreteCompany

- (instancetype)initWithName:(NSString *)name{
    self = [super initWithName:name];
    if (self) { 
        _childList = [NSMutableArray array];
    }
    return self;
}

- (void)add:(HCDCompany *)company{
    [self.childList addObject:company];
}

- (void)remove:(HCDCompany *)company{
    [self.childList removeObject:company];
}

- (void)display:(NSInteger)depth {
    NSString *seperate = @"";
    for (NSInteger i = 0; i < depth; i++) {
        seperate = [seperate stringByAppendingString:@"-"];
    }
    NSLog(@"%@%@的子公司",seperate,self.name);
    for (HCDCompany * company in self.childList) {
        [company display:depth + 2];
    }
}

- (void)lineofDuty{
    NSLog(@"%@的子公司的职责",self.name);
    for (HCDCompany * company in self.childList) {
        [company lineofDuty];
    }
}

@end
//HCDHRDepartment.h
@interface HCDHRDepartment : HCDCompany 

@end

//HCDHRDepartment.m
@implementation HCDHRDepartment

-(void)add:(HCDCompany *)company{
    
}

- (void)display:(NSInteger)depth {
    NSString *seperate = @"";
    for (NSInteger i = 0; i < depth; i++) {
        seperate = [seperate stringByAppendingString:@"-"];
    }
    NSLog(@"%@%@的HR部门",seperate,self.name);
}

-(void)remove:(HCDCompany *)company{

}

-(void)lineofDuty{
    NSLog(@"%@,培训员工",self.name);
}

@end
//HCDFinanceDepartment.h
@interface HCDFinanceDepartment : HCDCompany

@end

//HCDFinanceDepartment.m
@implementation HCDFinanceDepartment

-(void)add:(HCDCompany *)company{
    
}

-(void)remove:(HCDCompany *)company{
    
}

- (void)display:(NSInteger)depth {
    NSString *seperate = @"";
    for (NSInteger i = 0; i < depth; i++) {
        seperate = [seperate stringByAppendingString:@"-"];
    }
    NSLog(@"%@%@的财务部门",seperate,self.name);
}

-(void)lineofDuty{
    NSLog(@"%@,给员工发钱",self.name);
}

@end
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,542评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,596评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,021评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,682评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,792评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,985评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,107评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,845评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,299评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,612评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,747评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,441评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,072评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,828评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,069评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,545评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,658评论 2 350

推荐阅读更多精彩内容

  • 设计模式概述 在学习面向对象七大设计原则时需要注意以下几点:a) 高内聚、低耦合和单一职能的“冲突”实际上,这两者...
    彦帧阅读 3,737评论 0 14
  • 设计模式汇总 一、基础知识 1. 设计模式概述 定义:设计模式(Design Pattern)是一套被反复使用、多...
    MinoyJet阅读 3,922评论 1 15
  • 设计模式基本原则 开放-封闭原则(OCP),是说软件实体(类、模块、函数等等)应该可以拓展,但是不可修改。开-闭原...
    西山薄凉阅读 3,777评论 3 14
  • 字节跳动飞书内推!北京、杭州、武汉、广州、深圳、上海,六大城市等你来投。感兴趣的朋友可以私我咨询&内推,也可以通过...
    卢卡斯哔哔哔阅读 607评论 0 3
  • 链接:https://github.com/WiKi123/DesignPattern作者: WiKi123(gi...
    树懒啊树懒阅读 3,476评论 0 2