美文网首页
iOS 工厂模式的面向协议编程思想

iOS 工厂模式的面向协议编程思想

作者: aron1992 | 来源:发表于2017-12-09 21:06 被阅读20次

    UML概述

    UML简介

    UML (Unified Modeling Language)为面向对象软件设计提供统一的、标准的、可视化的建模语言。适用于描述以用例为驱动,以体系结构为中心的软件设计的全过程。

    UML的定义包括UML语义和UML表示法两个部分。

    1. UML语义:UML对语义的描述使开发者能在语义上取得一致认识,消除了因人而异的表达方法所造成的影响。
    2. UML表示法:UML表示法定义UML符号的表示法,为开发者或开发工具使用这 些图形符号和文本语法为系统建模提供了标准。

    UML模型图的构成

    1. 事物(Things):UML模型中最基本的构成元素,是具有代表性的成分的抽象
    2. 关系(Relationships):关系把事物紧密联系在一起
    3. 图(Diagrams ):图是事物和关系的可视化表示

    UML关系

    图例使用astah软件绘制

    1. 泛化 Generalization:

    子类继承父类的关系
    [站外图片上传中...(image-11e40b-1512824786008)]

    2. 实现 Relization:

    子类实现协议或者接口
    [站外图片上传中...(image-f48dac-1512824786008)]

    3. 依赖 Dependency:

    A类中应用了B类,这种关系具有偶然性和临时性,同时B类发生的变化会影响到A类
    [站外图片上传中...(image-602edf-1512824786008)]

    4. 双向关联 Association:

    一种特殊的依赖关系,比较强的依赖关系,一方依赖另一方
    集合映射的情况:
    1:单个
    0..1:单个或者没有
    1..:至少一个
    0..
    :0个或者多个
    *:任意个
    [站外图片上传中...(image-d11cb7-1512824786008)]

    5. 单向关联 Directed Associated:

    一种特殊的依赖关系,比较强的两者互为依赖关系
    [站外图片上传中...(image-391538-1512824786008)]

    6. 聚合关系 Aggregation:

    一种特殊的依赖关系,整体和部分的关系,各自有各自的生命周期,互不干扰,部分强调共享
    eg:电脑和电池的关系,电池是共享的,电池也有自己的生命周期
    [站外图片上传中...(image-7e2d9b-1512824786008)]

    7. 组合关系 Composition:

    一种特殊的依赖关系,整体和部分的关系,部分依赖于整体,不能独立于整体存在
    eg.公司和部门

    组合关系 Composition

    常用的UML

    类图

    • 属性的定义:
      <属性访问权限> <属性名> : <属性类型>
    • 属性访问权限定义:
      public:+
      protected:#
      package:~
      private:-
    • 定义一个私有的String类型的name属性:
    - name : String
    
    • 方法的定义:
      <方法访问权限> <方法名>([方法参数列表]) : <方法的返回值>
    • 方法访问权限定义:
      public:+
      protected:#
      package:~
      private:-
    • 定义一个公有的makeSound方法:
    + makeSound() : void
    

    [站外图片上传中...(image-f07a01-1512824786008)]

    用例图

    用例图是从用户角度描述系统功能, 是用户所能观察到的系统功能的模型图,用例是系统中的一个功能单元

    • 参与者与用例之间的关系

    关联: 表示参与者与用例之间的交互,通信途径。
    (关联有时候也用带箭头的实线来表示,这样的表示能够显示地表明发起用例的是参与者。)

    • 用例之间的关系

    包含<<include>>:箭头指向的用例为被包含的用例,称为包含用例;箭头出发的用例为基用例。包含用例是必选的,如果缺少包含用例,基用例就不完整;包含用例必须被执行,不需要满足某种条件;其执行并不会改变基用例的行为。
    扩展<<extend>>:箭头指向的用例为被扩展的用例,称为扩展用例;箭头出发的用例为基用例。扩展用例是可选的,如果缺少扩展用例,不会影响到基用例的完整性;扩展用例在一定条件下才会执行,并且其执行会改变基用例的行为。

    • 参与者之间的关系

    泛化:发出箭头的事物“is a”箭头指向的事物。泛化关系是一般和特殊关系,发出箭头的一方代表特殊的一方,箭头指向的一方代表一般一方。特殊一方继承了一般方的特性并增加了新的特性。
    [站外图片上传中...(image-a8769e-1512824786008)]

    时序图

    • 顺序图用来表示用例中的行为顺序。当执行一个用例行为时,顺序图中的每条消息对应了一个类操作或状态机中引起转换的事件。
    • 顺序图展示对象之间的交互,这些交互是指在场景或用例的事件流中发生的。 顺序图属于动态建模。
    • 顺序图的重点在消息序列上,也就是说,描述消息是如何在对象间发送和接收的。表示了对象之间传送消息的时间顺序。
    • 浏览顺序图的方法是:从上到下查看对象间交换的消息。

    以微信支付为例的一个时序图:
    [站外图片上传中...(image-8165a1-1512824786008)]### UML概述

    UML简介

    UML (Unified Modeling Language)为面向对象软件设计提供统一的、标准的、可视化的建模语言。适用于描述以用例为驱动,以体系结构为中心的软件设计的全过程。

    UML的定义包括UML语义和UML表示法两个部分。

    1. UML语义:UML对语义的描述使开发者能在语义上取得一致认识,消除了因人而异的表达方法所造成的影响。
    2. UML表示法:UML表示法定义UML符号的表示法,为开发者或开发工具使用这 些图形符号和文本语法为系统建模提供了标准。

    UML模型图的构成

    1. 事物(Things):UML模型中最基本的构成元素,是具有代表性的成分的抽象
    2. 关系(Relationships):关系把事物紧密联系在一起
    3. 图(Diagrams ):图是事物和关系的可视化表示

    UML关系

    图例使用astah软件绘制

    1. 泛化 Generalization:

    子类继承父类的关系
    [站外图片上传中...(image-11e40b-1512824786008)]

    2. 实现 Relization:

    子类实现协议或者接口
    [站外图片上传中...(image-f48dac-1512824786008)]

    3. 依赖 Dependency:

    A类中应用了B类,这种关系具有偶然性和临时性,同时B类发生的变化会影响到A类
    [站外图片上传中...(image-602edf-1512824786008)]

    4. 双向关联 Association:

    一种特殊的依赖关系,比较强的依赖关系,一方依赖另一方
    集合映射的情况:
    1:单个
    0..1:单个或者没有
    1..:至少一个
    0..
    :0个或者多个
    *:任意个
    [站外图片上传中...(image-d11cb7-1512824786008)]

    5. 单向关联 Directed Associated:

    一种特殊的依赖关系,比较强的两者互为依赖关系
    [站外图片上传中...(image-391538-1512824786008)]

    6. 聚合关系 Aggregation:

    一种特殊的依赖关系,整体和部分的关系,各自有各自的生命周期,互不干扰,部分强调共享
    eg:电脑和电池的关系,电池是共享的,电池也有自己的生命周期
    [站外图片上传中...(image-7e2d9b-1512824786008)]

    7. 组合关系 Composition:

    一种特殊的依赖关系,整体和部分的关系,部分依赖于整体,不能独立于整体存在
    eg.公司和部门
    [站外图片上传中...(image-73e2-1512824786008)]

    常用的UML

    类图

    • 属性的定义:
      <属性访问权限> <属性名> : <属性类型>
    • 属性访问权限定义:
      public:+
      protected:#
      package:~
      private:-
    • 定义一个私有的String类型的name属性:
    - name : String
    
    • 方法的定义:
      <方法访问权限> <方法名>([方法参数列表]) : <方法的返回值>
    • 方法访问权限定义:
      public:+
      protected:#
      package:~
      private:-
    • 定义一个公有的makeSound方法:
    + makeSound() : void
    

    [站外图片上传中...(image-f07a01-1512824786008)]

    用例图

    用例图是从用户角度描述系统功能, 是用户所能观察到的系统功能的模型图,用例是系统中的一个功能单元

    • 参与者与用例之间的关系

    关联: 表示参与者与用例之间的交互,通信途径。
    (关联有时候也用带箭头的实线来表示,这样的表示能够显示地表明发起用例的是参与者。)

    • 用例之间的关系

    包含<<include>>:箭头指向的用例为被包含的用例,称为包含用例;箭头出发的用例为基用例。包含用例是必选的,如果缺少包含用例,基用例就不完整;包含用例必须被执行,不需要满足某种条件;其执行并不会改变基用例的行为。
    扩展<<extend>>:箭头指向的用例为被扩展的用例,称为扩展用例;箭头出发的用例为基用例。扩展用例是可选的,如果缺少扩展用例,不会影响到基用例的完整性;扩展用例在一定条件下才会执行,并且其执行会改变基用例的行为。

    • 参与者之间的关系

    泛化:发出箭头的事物“is a”箭头指向的事物。泛化关系是一般和特殊关系,发出箭头的一方代表特殊的一方,箭头指向的一方代表一般一方。特殊一方继承了一般方的特性并增加了新的特性。

    用例图

    时序图

    • 顺序图用来表示用例中的行为顺序。当执行一个用例行为时,顺序图中的每条消息对应了一个类操作或状态机中引起转换的事件。
    • 顺序图展示对象之间的交互,这些交互是指在场景或用例的事件流中发生的。 顺序图属于动态建模。
    • 顺序图的重点在消息序列上,也就是说,描述消息是如何在对象间发送和接收的。表示了对象之间传送消息的时间顺序。
    • 浏览顺序图的方法是:从上到下查看对象间交换的消息。

    以微信支付为例的一个时序图:
    [站外图片上传中...(image-8165a1-1512824786008)]### UML概述

    UML简介

    UML (Unified Modeling Language)为面向对象软件设计提供统一的、标准的、可视化的建模语言。适用于描述以用例为驱动,以体系结构为中心的软件设计的全过程。

    UML的定义包括UML语义和UML表示法两个部分。

    1. UML语义:UML对语义的描述使开发者能在语义上取得一致认识,消除了因人而异的表达方法所造成的影响。
    2. UML表示法:UML表示法定义UML符号的表示法,为开发者或开发工具使用这 些图形符号和文本语法为系统建模提供了标准。

    UML模型图的构成

    1. 事物(Things):UML模型中最基本的构成元素,是具有代表性的成分的抽象
    2. 关系(Relationships):关系把事物紧密联系在一起
    3. 图(Diagrams ):图是事物和关系的可视化表示

    UML关系

    图例使用astah软件绘制

    1. 泛化 Generalization:

    子类继承父类的关系
    [站外图片上传中...(image-11e40b-1512824786008)]

    2. 实现 Relization:

    子类实现协议或者接口
    [站外图片上传中...(image-f48dac-1512824786008)]

    3. 依赖 Dependency:

    A类中应用了B类,这种关系具有偶然性和临时性,同时B类发生的变化会影响到A类
    [站外图片上传中...(image-602edf-1512824786008)]

    4. 双向关联 Association:

    一种特殊的依赖关系,比较强的依赖关系,一方依赖另一方
    集合映射的情况:
    1:单个
    0..1:单个或者没有
    1..:至少一个
    0..
    :0个或者多个
    *:任意个
    [站外图片上传中...(image-d11cb7-1512824786008)]

    5. 单向关联 Directed Associated:

    一种特殊的依赖关系,比较强的两者互为依赖关系

    关联 Association

    6. 聚合关系 Aggregation:

    一种特殊的依赖关系,整体和部分的关系,各自有各自的生命周期,互不干扰,部分强调共享
    eg:电脑和电池的关系,电池是共享的,电池也有自己的生命周期
    [站外图片上传中...(image-7e2d9b-1512824786008)]

    7. 组合关系 Composition:

    一种特殊的依赖关系,整体和部分的关系,部分依赖于整体,不能独立于整体存在
    eg.公司和部门
    [站外图片上传中...(image-73e2-1512824786008)]

    常用的UML

    类图

    • 属性的定义:
      <属性访问权限> <属性名> : <属性类型>
    • 属性访问权限定义:
      public:+
      protected:#
      package:~
      private:-
    • 定义一个私有的String类型的name属性:
    - name : String
    
    • 方法的定义:
      <方法访问权限> <方法名>([方法参数列表]) : <方法的返回值>
    • 方法访问权限定义:
      public:+
      protected:#
      package:~
      private:-
    • 定义一个公有的makeSound方法:
    + makeSound() : void
    

    [站外图片上传中...(image-f07a01-1512824786008)]

    用例图

    用例图是从用户角度描述系统功能, 是用户所能观察到的系统功能的模型图,用例是系统中的一个功能单元

    • 参与者与用例之间的关系

    关联: 表示参与者与用例之间的交互,通信途径。
    (关联有时候也用带箭头的实线来表示,这样的表示能够显示地表明发起用例的是参与者。)

    • 用例之间的关系

    包含<<include>>:箭头指向的用例为被包含的用例,称为包含用例;箭头出发的用例为基用例。包含用例是必选的,如果缺少包含用例,基用例就不完整;包含用例必须被执行,不需要满足某种条件;其执行并不会改变基用例的行为。
    扩展<<extend>>:箭头指向的用例为被扩展的用例,称为扩展用例;箭头出发的用例为基用例。扩展用例是可选的,如果缺少扩展用例,不会影响到基用例的完整性;扩展用例在一定条件下才会执行,并且其执行会改变基用例的行为。

    • 参与者之间的关系

    泛化:发出箭头的事物“is a”箭头指向的事物。泛化关系是一般和特殊关系,发出箭头的一方代表特殊的一方,箭头指向的一方代表一般一方。特殊一方继承了一般方的特性并增加了新的特性。
    [站外图片上传中...(image-a8769e-1512824786008)]

    时序图

    • 顺序图用来表示用例中的行为顺序。当执行一个用例行为时,顺序图中的每条消息对应了一个类操作或状态机中引起转换的事件。
    • 顺序图展示对象之间的交互,这些交互是指在场景或用例的事件流中发生的。 顺序图属于动态建模。
    • 顺序图的重点在消息序列上,也就是说,描述消息是如何在对象间发送和接收的。表示了对象之间传送消息的时间顺序。
    • 浏览顺序图的方法是:从上到下查看对象间交换的消息。

    以微信支付为例的一个时序图:
    [站外图片上传中...(image-8165a1-1512824786008)]### UML概述

    UML简介

    UML (Unified Modeling Language)为面向对象软件设计提供统一的、标准的、可视化的建模语言。适用于描述以用例为驱动,以体系结构为中心的软件设计的全过程。

    UML的定义包括UML语义和UML表示法两个部分。

    1. UML语义:UML对语义的描述使开发者能在语义上取得一致认识,消除了因人而异的表达方法所造成的影响。
    2. UML表示法:UML表示法定义UML符号的表示法,为开发者或开发工具使用这 些图形符号和文本语法为系统建模提供了标准。

    UML模型图的构成

    1. 事物(Things):UML模型中最基本的构成元素,是具有代表性的成分的抽象
    2. 关系(Relationships):关系把事物紧密联系在一起
    3. 图(Diagrams ):图是事物和关系的可视化表示

    UML关系

    图例使用astah软件绘制

    1. 泛化 Generalization:

    子类继承父类的关系
    [站外图片上传中...(image-11e40b-1512824786008)]

    2. 实现 Relization:

    子类实现协议或者接口
    [站外图片上传中...(image-f48dac-1512824786008)]

    3. 依赖 Dependency:

    A类中应用了B类,这种关系具有偶然性和临时性,同时B类发生的变化会影响到A类
    [站外图片上传中...(image-602edf-1512824786008)]

    4. 双向关联 Association:

    一种特殊的依赖关系,比较强的依赖关系,一方依赖另一方
    集合映射的情况:
    1:单个
    0..1:单个或者没有
    1..:至少一个
    0..
    :0个或者多个
    *:任意个
    [站外图片上传中...(image-d11cb7-1512824786008)]

    5. 单向关联 Directed Associated:

    一种特殊的依赖关系,比较强的两者互为依赖关系
    [站外图片上传中...(image-391538-1512824786008)]

    6. 聚合关系 Aggregation:

    一种特殊的依赖关系,整体和部分的关系,各自有各自的生命周期,互不干扰,部分强调共享
    eg:电脑和电池的关系,电池是共享的,电池也有自己的生命周期
    [站外图片上传中...(image-7e2d9b-1512824786008)]

    7. 组合关系 Composition:

    一种特殊的依赖关系,整体和部分的关系,部分依赖于整体,不能独立于整体存在
    eg.公司和部门
    [站外图片上传中...(image-73e2-1512824786008)]

    常用的UML

    类图

    • 属性的定义:
      <属性访问权限> <属性名> : <属性类型>
    • 属性访问权限定义:
      public:+
      protected:#
      package:~
      private:-
    • 定义一个私有的String类型的name属性:
    - name : String
    
    • 方法的定义:
      <方法访问权限> <方法名>([方法参数列表]) : <方法的返回值>
    • 方法访问权限定义:
      public:+
      protected:#
      package:~
      private:-
    • 定义一个公有的makeSound方法:
    + makeSound() : void
    
    泛化 Generalization

    用例图

    用例图是从用户角度描述系统功能, 是用户所能观察到的系统功能的模型图,用例是系统中的一个功能单元

    • 参与者与用例之间的关系

    关联: 表示参与者与用例之间的交互,通信途径。
    (关联有时候也用带箭头的实线来表示,这样的表示能够显示地表明发起用例的是参与者。)

    • 用例之间的关系

    包含<<include>>:箭头指向的用例为被包含的用例,称为包含用例;箭头出发的用例为基用例。包含用例是必选的,如果缺少包含用例,基用例就不完整;包含用例必须被执行,不需要满足某种条件;其执行并不会改变基用例的行为。
    扩展<<extend>>:箭头指向的用例为被扩展的用例,称为扩展用例;箭头出发的用例为基用例。扩展用例是可选的,如果缺少扩展用例,不会影响到基用例的完整性;扩展用例在一定条件下才会执行,并且其执行会改变基用例的行为。

    • 参与者之间的关系

    泛化:发出箭头的事物“is a”箭头指向的事物。泛化关系是一般和特殊关系,发出箭头的一方代表特殊的一方,箭头指向的一方代表一般一方。特殊一方继承了一般方的特性并增加了新的特性。
    [站外图片上传中...(image-a8769e-1512824786008)]

    时序图

    • 顺序图用来表示用例中的行为顺序。当执行一个用例行为时,顺序图中的每条消息对应了一个类操作或状态机中引起转换的事件。
    • 顺序图展示对象之间的交互,这些交互是指在场景或用例的事件流中发生的。 顺序图属于动态建模。
    • 顺序图的重点在消息序列上,也就是说,描述消息是如何在对象间发送和接收的。表示了对象之间传送消息的时间顺序。
    • 浏览顺序图的方法是:从上到下查看对象间交换的消息。

    以微信支付为例的一个时序图:
    [站外图片上传中...(image-8165a1-1512824786008)]### UML概述

    UML简介

    UML (Unified Modeling Language)为面向对象软件设计提供统一的、标准的、可视化的建模语言。适用于描述以用例为驱动,以体系结构为中心的软件设计的全过程。

    UML的定义包括UML语义和UML表示法两个部分。

    1. UML语义:UML对语义的描述使开发者能在语义上取得一致认识,消除了因人而异的表达方法所造成的影响。
    2. UML表示法:UML表示法定义UML符号的表示法,为开发者或开发工具使用这 些图形符号和文本语法为系统建模提供了标准。

    UML模型图的构成

    1. 事物(Things):UML模型中最基本的构成元素,是具有代表性的成分的抽象
    2. 关系(Relationships):关系把事物紧密联系在一起
    3. 图(Diagrams ):图是事物和关系的可视化表示

    UML关系

    图例使用astah软件绘制

    1. 泛化 Generalization:

    子类继承父类的关系
    [站外图片上传中...(image-11e40b-1512824786008)]

    2. 实现 Relization:

    子类实现协议或者接口
    [站外图片上传中...(image-f48dac-1512824786008)]

    3. 依赖 Dependency:

    A类中应用了B类,这种关系具有偶然性和临时性,同时B类发生的变化会影响到A类
    [站外图片上传中...(image-602edf-1512824786008)]

    4. 双向关联 Association:

    一种特殊的依赖关系,比较强的依赖关系,一方依赖另一方
    集合映射的情况:
    1:单个
    0..1:单个或者没有
    1..:至少一个
    0..
    :0个或者多个
    *:任意个
    [站外图片上传中...(image-d11cb7-1512824786008)]

    5. 单向关联 Directed Associated:

    一种特殊的依赖关系,比较强的两者互为依赖关系
    [站外图片上传中...(image-391538-1512824786008)]

    6. 聚合关系 Aggregation:

    一种特殊的依赖关系,整体和部分的关系,各自有各自的生命周期,互不干扰,部分强调共享
    eg:电脑和电池的关系,电池是共享的,电池也有自己的生命周期
    [站外图片上传中...(image-7e2d9b-1512824786008)]

    7. 组合关系 Composition:

    一种特殊的依赖关系,整体和部分的关系,部分依赖于整体,不能独立于整体存在
    eg.公司和部门
    [站外图片上传中...(image-73e2-1512824786008)]

    常用的UML

    类图

    • 属性的定义:
      <属性访问权限> <属性名> : <属性类型>
    • 属性访问权限定义:
      public:+
      protected:#
      package:~
      private:-
    • 定义一个私有的String类型的name属性:
    - name : String
    
    • 方法的定义:
      <方法访问权限> <方法名>([方法参数列表]) : <方法的返回值>
    • 方法访问权限定义:
      public:+
      protected:#
      package:~
      private:-
    • 定义一个公有的makeSound方法:
    + makeSound() : void
    

    [站外图片上传中...(image-f07a01-1512824786008)]

    用例图

    用例图是从用户角度描述系统功能, 是用户所能观察到的系统功能的模型图,用例是系统中的一个功能单元

    • 参与者与用例之间的关系

    关联: 表示参与者与用例之间的交互,通信途径。
    (关联有时候也用带箭头的实线来表示,这样的表示能够显示地表明发起用例的是参与者。)

    • 用例之间的关系

    包含<<include>>:箭头指向的用例为被包含的用例,称为包含用例;箭头出发的用例为基用例。包含用例是必选的,如果缺少包含用例,基用例就不完整;包含用例必须被执行,不需要满足某种条件;其执行并不会改变基用例的行为。
    扩展<<extend>>:箭头指向的用例为被扩展的用例,称为扩展用例;箭头出发的用例为基用例。扩展用例是可选的,如果缺少扩展用例,不会影响到基用例的完整性;扩展用例在一定条件下才会执行,并且其执行会改变基用例的行为。

    • 参与者之间的关系

    泛化:发出箭头的事物“is a”箭头指向的事物。泛化关系是一般和特殊关系,发出箭头的一方代表特殊的一方,箭头指向的一方代表一般一方。特殊一方继承了一般方的特性并增加了新的特性。
    [站外图片上传中...(image-a8769e-1512824786008)]

    时序图

    • 顺序图用来表示用例中的行为顺序。当执行一个用例行为时,顺序图中的每条消息对应了一个类操作或状态机中引起转换的事件。
    • 顺序图展示对象之间的交互,这些交互是指在场景或用例的事件流中发生的。 顺序图属于动态建模。
    • 顺序图的重点在消息序列上,也就是说,描述消息是如何在对象间发送和接收的。表示了对象之间传送消息的时间顺序。
    • 浏览顺序图的方法是:从上到下查看对象间交换的消息。

    以微信支付为例的一个时序图:

    时序图 #### 前言
    OOP开发有个原则是针对抽象编程而不是针对具体编程,实际的软件开发中,因为时间和项目进度等客观不可抵抗和主观的因素,我们偏向使用最简单的的方式去实现功能,而没有考虑到未来可能会有的扩展问题,导致未来发生扩展的时候出现了维护性的灾难,软件模块不好扩展,需求变动就得修改模块,这就违反了开闭原则,所以,很有必要在设计的时候去考虑未来可能会引入的变化,使用合适的模式去应对未来的这种变化。

    简单工厂

    简单工厂作为工厂模式的最简单的一种,与其说是一种模式,不如说是一种编程习惯,软件开发中,我们会无意识或者有意思的把经常用到的那部分内容抽取到一个模块中统一创建,而不是在多个使用者单独的创建,这也遵循软件开发中的don't repeat yourself原则,一般的我们会把创建的方法定义为静态的方法,如果内容有差异,一般滴我们会使用类型进行区分,比如下面代码,我们创建不同类型的mapview对象,这是一个典型的简单工厂的例子。

    //
    //  SimpleMapFactory.h
    //  DesignPatternProject
    //
    //  Created by aron on 2017/5/18.
    //  Copyright © 2017年 aron. All rights reserved.
    //
    
    #import <Foundation/Foundation.h>
    #import <UIKit/UIKit.h>
    
    typedef NS_ENUM(NSUInteger, MapType) {
        MapTypeBaidu,
        MapTypeGaode,
        MapTypeTencent,
    };
    
    @interface SimpleMapFactory : NSObject
    
    + (UIView*)mapViewWithFrame:(CGRect)frame type:(MapType)mapType;
    
    @end
    
    
    //
    //  SimpleMapFactory.m
    //  DesignPatternProject
    //
    //  Created by aron on 2017/5/18.
    //  Copyright © 2017年 aron. All rights reserved.
    //
    
    #import "SimpleMapFactory.h"
    #import <MAMapKit/MAMapKit.h>
    #import <AMapFoundationKit/AMapFoundationKit.h>
    #import <BaiduMapAPI_Map/BMKMapView.h>
    
    
    @implementation SimpleMapFactory
    
    + (UIView*)mapViewWithFrame:(CGRect)frame type:(MapType)mapType {
        if (mapType == MapTypeGaode) {
            MAMapView *maMapView = [[MAMapView alloc] initWithFrame:frame];
            return maMapView;
        } else if (mapType == MapTypeBaidu) {
            BMKMapView* mapView = [[BMKMapView alloc]initWithFrame:frame];
            return mapView;
        }
        
        return nil;
    }
    
    @end
    

    简单工厂的局限

    定义一个静态方法+ (UIView*)mapViewWithFrame:(CGRect)frame type:(MapType)mapType,实现中使用分支语句创建不同的实例,如果后面有其他类型的实例,那么这个方法就得进行相应的修改,如果类型变得多了,创建的过程复杂了,这个模块就得经常的修改,这还没什么,简单工厂返回的是一个UIView的通用类型,使用者需要强转为对应的类型,才能充分的使用到这个UIView对象,在这个场景中MAMapViewBMKMapView这两个类的接口是完全不同的,这意味着,添加了一个新类型,修改的不仅仅是工厂静态方法,调用者的使用方式也必须进行相应的修改,违法了开闭原则,让维护和扩展变得困难起来了,这不是我们想要的。

    工厂方法

    工厂方法是对简单工厂的抽象,让工厂具有了良好的扩展性,使得容易扩展和维护,工厂方法抽象了两个方面,首先对产品进行了抽象,在上面的案例中就是对mapview进行了抽象,在抽象了mapview中定义公共的接口提供给调用者使用;其次对工厂进行了抽象,工厂返回的不是一个具体的mapview,而是抽象之后的mapview,调用者可以使用抽象的mapview种定义的公共的接口和具体的mapview对象交互。
    工厂方法的UML描述如下:

    工厂方法类图工厂方法类图

    工厂方法代码实现

    • 对产品的抽象
    #import <Foundation/Foundation.h>
    #import <UIKit/UIKit.h>
    
    @protocol MapView <NSObject>
    
    - (instancetype)initWithFrame:(CGRect)frame;
    
    - (UIView*)getView;
    
    @end
    
    • 对工厂的抽象
    #import <Foundation/Foundation.h>
    #import "MapView.h"
    
    @protocol MapFactory <NSObject>
    
    + (id<MapView>)mapViewWithFrame:(CGRect)frame;
    
    @end
    
    • 具体的产品,以百度地图为例
    #import "BaiduMapView.h"
    #import <BaiduMapAPI_Map/BMKMapView.h>
    
    @interface BaiduMapView () {
        BMKMapView* _mapView;
    }
    
    @end
    
    @implementation BaiduMapView
    
    - (instancetype)initWithFrame:(CGRect)frame {
        self = [super init];
        if (self) {
            BMKMapView* mapView = [[BMKMapView alloc]initWithFrame:frame];
            _mapView = mapView;
        }
        return self;
    }
    
    - (UIView *)getView {
        return _mapView;
    }
    
    @end
    
    • 具体的工厂(百度地图创建工厂)
    #import "BaiduMapView.h"
    #import <BaiduMapAPI_Map/BMKMapView.h>
    
    @interface BaiduMapView () {
        BMKMapView* _mapView;
    }
    
    @end
    
    @implementation BaiduMapView
    
    - (instancetype)initWithFrame:(CGRect)frame {
        self = [super init];
        if (self) {
            BMKMapView* mapView = [[BMKMapView alloc]initWithFrame:frame];
            _mapView = mapView;
        }
        return self;
    }
    
    - (UIView *)getView {
        return _mapView;
    }
    
    @end
    

    上面的代码片段就是一个简单的工厂方法的例子,抽象的产品只提供了一个接口,真是的场景使用到的不止一个公有接口,因需求而定。

    • 调用者的调用方式
        id<MapView> mapView = [BaiduMapFactory mapViewWithFrame:CGRectMake(0, 0, 320, 200)];
        [self.view addSubview:[mapView getView]];
        
        id<MapView> maMapView = [GaodeMapFactory mapViewWithFrame:CGRectMake(0, 200, 320, 200)];
        [self.view addSubview:[maMapView getView]];
    

    当需求有变化需要替换底层组件,调用者只要修改工厂就行了,需要添加相应的具体产品和具体的工厂就行了,不会依赖于具体的实现,扩展起来相当的方便,当然,因为抽象级别的提高,代码量也会相应的变多,不过这是必要的牺牲,鱼和熊掌不可兼得。

    抽象工厂

    工厂方法返回的是多个同种类型的对象,未来的扩展我们可能会遇到返回的是一组同种类型的对象,比如在我们的软件场景中,我么未来可能扩展我们的工厂返回定位对象,这种场景,需要定义一个定位对象的协议,工厂协议需要添加一个公共接口返回一个定位对象,这样工厂方法转换为了抽象工厂,可以这么说抽象工厂是对工厂方法的再次抽象和扩展。
    抽象工厂的UML描述如下:

    抽象工厂类图抽象工厂类图

    抽象工厂代码实现

    抽象工厂在工厂方法的基础上进行了扩展,添加了两部分:1、添加了一个Location抽象接口和Location对应的实现;2、工厂的接口添加了一个返回Location对象的公有方法。下面代码只展示了新增加的部分,完整的代码可以查看文章底部的链接。

    • Location抽象接口
    #import <Foundation/Foundation.h>
    #import <CoreLocation/CoreLocation.h>
    
    @protocol AbsLocation <NSObject>
    
    - (void)startLocateWithResult:(void(^)(CLLocation* location))complete;
    
    @end
    
    • 工厂的接口添加了一个返回Location对象的公有方法
    @protocol AbsMapFactory <NSObject>
    
    + (id<AbsMapView>)mapViewWithFrame:(CGRect)frame;
    
    + (id<AbsLocation>)location;
    
    @end
    
    • Location抽象接口的实现,例子只是模拟,真正的以实际的定位对象为准
    
    //.h
    
    #import <Foundation/Foundation.h>
    #import "AbsLocation.h"
    
    @interface AbsBaiduLocation : NSObject <AbsLocation>
    
    @end
    
    .m
    
    #import "AbsBaiduLocation.h"
    
    @implementation AbsBaiduLocation
    
    - (void)startLocateWithResult:(void(^)(CLLocation* location))complete {
        NSLog(@"BaiduLocation started");
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            // 模拟返回
            !complete ?: complete([[CLLocation alloc] initWithLatitude:123 longitude:123]);
        });
    }
    @end
    

    使用方法:

     // abstract factory usuage
        id<AbsMapView> absBaiduMapView = [AbsBaiduMapFactory mapViewWithFrame:CGRectMake(0, 0, 320, 200)];
        [self.view addSubview:[absBaiduMapView getView]];
        id<AbsLocation> baiduMapLocation = [AbsBaiduMapFactory location];
        [baiduMapLocation startLocateWithResult:^(CLLocation *location) {
            NSLog(@"location result");
        }];
        
        
        id<AbsMapView> absGaodeMapView = [AbsGaodeMapFactory mapViewWithFrame:CGRectMake(0, 200, 320, 200)];
        [self.view addSubview:[absGaodeMapView getView]];
    

    总结

    工厂模式在实际软件开发中使用的场景是很多的,如果在可预见的未来软件会很有可能发生扩展变化,那么引入工厂方法或者抽象工厂设计出良好扩展的模块还是很有必要的,如果这个模块相对固定不容易改变,那么使用工厂方法也没什么问题,毕竟简单高效才是王道,引入模式反而把问题复杂化了,维护起来工作量反而大了,一点个人不成熟的想法,以上。

    相关链接

    本文Demo源码传送门>>>

    相关文章

      网友评论

          本文标题:iOS 工厂模式的面向协议编程思想

          本文链接:https://www.haomeiwen.com/subject/ylmpixtx.html