iOS -- 工厂设计模式

news2025/1/16 0:55:57

iOS -- 工厂设计模式

  • 设计模式概念
  • 设计模式七大准则
  • 简单工厂模式
    • 优点
    • 缺点
    • 主要作用
    • 示例
  • 工厂方法模式
    • 优点
    • 缺点
    • 主要作用:
  • 抽象工厂方法
    • 缺点
    • 主要作用:
    • 文件分类

设计模式概念

所谓设计模式(Design pattern) 是解决软件开发某些特定问题而提出的一些解决方案也可以理解成解决问题的一些思路。通过设计模式可以帮助我们增强代码的可重用性、可扩充性、 可维护性、灵活性好。我们使用设计模式最终的目的是实现代码的 高内聚 和 低耦合。可以这么说,计算机中设计模式指的是一套广为人知、被反复使用、经过分类编目的代码设计经验。使用设计模式是为了可重用代码,让代码更容易被他人理解,最重要的是保证代码可靠性。

设计模式七大准则

  1. 单一职责原则(Single Responsibility Principle):一个类应该只有一个引起它变化的原因。每个类应该负责单一的职责,这样可以提高类的内聚性和可维护性
    比如:UIView负责事件的传递、响应,CALayer负责视图的显示、动画,他们各自都有自己的单一职责。
  2. 开放封闭原则(Open-Closed Principle):软件实体(类、模块、函数等)应该**对扩展开放,对修改封闭。**通过使用抽象和接口,可以在不修改现有代码的情况下扩展系统的功能。
  3. 里氏替换原则(Liskov Substitution Principle):子类对象应该能够替换其父类对象,而程序的行为不受影响。这个原则强调了继承关系的正确使用,确保子类符合父类的接口和行为。
  4. 依赖倒置原则(Dependency Inversion Principle):高层模块不应该依赖于低层模块,二者都应该依赖于抽象。抽象应该依赖于细节,而不是细节依赖于抽象。
  5. 接口隔离原则(Interface Segregation Principle):客户端不应该被迫依赖它们不使用的接口。接口应该尽量小而精确,符合客户端的实际需求。
    我们在 Objective-C 中实现了接口和类的定义,遵循了拆分接口的原则。每个类只需实现相关的方法,避免了不必要的方法实现,提高了代码的可读性和灵活性。
  6. 迪米特法则(Law of Demeter):一个对象应该与其他对象保持最少的知识联系。一个类应该尽量减少对其他类的依赖,只与直接相关的类进行交互。
  7. 组合/聚合复用原则(Composition/Aggregation Reuse Principle):优先使用组合和聚合关系,而不是继承关系来实现代码的复用。通过组合和聚合,可以使得系统更灵活、可扩展和易于维护。
    合成: 表示一个类拥有其他类的实例,并且这些实例是无法独立存在的一部分。当一个对象被销毁时,其组成部分也会被销毁。
@interface Engine : NSObject
// 引擎类的定义
@end

@interface Car : NSObject
@property (nonatomic, strong) Engine *engine;
// 车类的定义,拥有一个引擎实例作为其一部分
@end

@implementation Car
// 类的实现
@end

Car类持有一个引擎(Engine)对象的实例作为其一部分。当Car对象被销毁时,引擎对象也会随之被销毁。
**聚合:**表示一个类与其他类之间存在关联关系,其中一个类是另一个类的容器或集合,但这些类之间的关系并不是强依赖的关系。当一个对象被销毁时,其聚合对象可以继续存在。

@interface Student : NSObject
// 学生类的定义
@end

@interface Classroom : NSObject
@property (nonatomic, strong) NSArray<Student *> *students;
// 教室类的定义,包含了学生对象的集合
@end

@implementation Classroom
// 类的实现
@end

Classroom类包含一个学生对象的数组作为其一部分。当Classroom对象被销毁时,学生对象仍然可以存在,因为它们可以属于其他教室或独立存在。

合成和聚合都描述了类之间的关系,合成表示一个类拥有其他类的实例作为其一部分,而聚合表示一个类与其他类之间存在关联关系,其中一个类是另一个类的容器或集合。

简单工厂模式

在这里插入图片描述
专门定义一个类(工厂类)来负责创建其他类的实例。可以根据创建方法的参数来返回不同类的实例,被创建的实例通常具有共同的父类。(总结来说就是把一大堆if-else判断由业务层放到工厂类里面)。

优点

  • 根据约定好的参数就可以获取所需要的对象,而不需要知道其创建的细节。减少了系统的耦合度。
  • 客户端无须知道所创建的具体产品类的类名,只需要知道具体产品类所对应的参数即可,减少开发者的记忆成本。

缺点

  • 如果业务上添加新产品的话,就需要修改工厂类原有的判断逻辑,这其实是违背了开闭原则的。
  • 在产品类型较多时,有可能造成工厂逻辑过于复杂。所以简单工厂模式比较适合产品种类比较少而且增多的概率很低的情况。

主要作用

它提供了一种通过一个工厂类来创建对象的方式,而不需要直接在客户端代码中实例化对象。简单工厂模式将对象的创建和使用分离,使得客户端代码更加灵活,并且可以降低代码的耦合度。

  • 有一组相似的对象,需要集中统一创建时。
  • 创建对象的过程较为复杂时。
  • 对象很多,并且有扩展需求时。
  • 客户端不需要知道创建对象的过程时。
  • 客户端使用的对象存在变动的可能,或者根本不知道使用哪一个具体对象时。

示例

工厂类中的核心代码
通过传递进来的字符串来确定生成的类。

//  phoneFactory.m
//  简单工厂模式
//
//  Created by mac on 2024/4/18.
//

#import "phoneFactory.h"
#import "Vivo.h"
#import "Oppo.h"
#import "Xiaomi.h"
#import "Apple.h"
@implementation phoneFactory

NSArray* array = @[@"Vivo", @"Oppo", @"Xiaomi", @"Apple"];
+ (nonnull id)createPhone:(nonnull NSString *)phoneType {
    switch ([array indexOfObject:phoneType]) {
        case 0:
            return [[Vivo alloc] init];
            break;
        case 1:
            return [[Oppo alloc] init];
            break;
        case 2:
            return [[Xiaomi alloc] init];
            break;
        case 3:
            return [[Apple alloc] init];
        default:
            break;
    }
    
    return nil;
}

@end

其中通过工厂类返回的各种类(各种型号手机)必须遵守以下协议:

@protocol phoneDelegate <NSObject>
- (void) phoneWays;
@end

然后在各个类中实现该方法

#import "Vivo.h"

@implementation Vivo
- (void) phoneWays {
    NSLog(@"Vivo");
}
@end

文件分类:
在这里插入图片描述
实现效果:
在这里插入图片描述
在这里插入图片描述
这样的模式就与类族模式有点相似,类族模式最重要的一点是:把实现细节隐藏在一套简单的公共接口后面,并且类之间为继承关系。学习完工厂模式之后,简单工厂方法和类族模式主要的区别是:生成的各类和工厂类并不是父子类的关系,通过协议来完成各方法。

工厂方法模式

定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使得一个类的实例化延迟到了子类。就像Cocoa Touch中的NSNumber的numberWithBool和numberWithInt方法,他们传入不同类型的参数,获得NSNumber实例。
在这里插入图片描述

优点

  • 和直接创建具体对象相比,使用工厂方法创建对象算是最佳的做法。
  • 根据所需产品找对应工厂进行生产,不关心产品细节,也不需要知道产品类的类名。
  • 当系统中加入新产品时,不需要修改抽象工厂和抽象产品提供的接口,也无须修改客户端和其他的具体工厂和具体产品,而只要添加一个具体工厂和与其对应的具体产品就可以了,符合了“开-闭”原则。

缺点

当系统中加入新产品时,除了需要提供新的产品类之外,还要提供与其对应的具体工厂类。因此系统中类的个数将成对增加,增加了系统的复杂度。

主要作用:

  • 编译时无法准确预期需要创建对象的类。
  • 类想要其子类决定在运行时创建什么类型的实例。
  • 类有若干辅助类为其子类,而你想将返回哪个子类这种信息局部化。

示例:
这个较之前的相比,工厂类中并没有类方法,只有一些方法,简单工厂方法是通过协议的方法去令其他类完成方法,而工厂方法模式是通过继承,令其他类继承工厂类,去重写父类的这几个方法。 来看看代码:

工厂类:

#import "phoneCenter.h"

@implementation phoneCenter
- (void) beginProductionPhone {
    NSLog(@"begin");
}

- (void) succeedProductionPhone {
    NSLog(@"succeed");
}
@end

子类:

@interface Vivo : phoneCenter

@end

#import "Vivo.h"

@implementation Vivo
- (void) beginProductionPhone {
    NSLog(@"begin vivo");
}

- (void) succeedProductionPhone {
    NSLog(@"succeed vivo");
}
@end

在viewController中初始化时以父类编译,子类运行

        PhoneCenter *a = [[Vivo alloc] init];
        [a beginProductionPhone];
        [a succeedProductionPhone];

文件分类
在这里插入图片描述
效果实现:
在这里插入图片描述

抽象工厂方法

工厂方法模式只有一个抽象产品类,而抽象工厂模式有多个抽象产品类。抽象工厂模式里每个工厂都会生产多种产品,但不同工厂生产的产品属于不同的系列。抽象工厂模式可以用来解决多产品族的问题。
在这里插入图片描述

缺点

  • 增加新的产品种类困难,它需要修改抽象工厂的接口。
  • 代码结构比较复杂。

主要作用:

  • 类想让其子类决定在运行时创建什么,无法在编译时准确确定。
  • 类有若干个辅助类为其子类,而你想将返回某个子类这一信息局部化。

文件分类

在这里插入图片描述
这次的分类就较之前复杂了很多,我们来一步步看:
首先Manager相当于最大的工厂类,通过这个函数来确定是哪个工厂,apple厂还是google厂:

#import "FactoryManager.h"
#import "GooleFactory.h"
#import "AppleFactory.h"
@implementation FactoryManager

+ (BaseFactory *)factoryWithType:(KFactoryType)factoryType {
    if (factoryType == KApple) {
        return [[AppleFactory alloc] init];
    } else if (factoryType == KGoogle) {
        return [[GooleFactory alloc] init];
    }
    return nil;
}

@end

接下来到了工厂这步:
首先有一个作为两家工厂的父类,两家工厂继承于此类,并重写此基础类的各方法,以此来展示不同的效果:

#import <Foundation/Foundation.h>
#import "BasePhone.h"
#import "BaseWatch.h"
NS_ASSUME_NONNULL_BEGIN

@interface BaseFactory : NSObject
- (BasePhone*)createPhone;
- (BaseWatch*)createWatch;
@end

#import "BaseFactory.h"

@implementation BaseFactory

- (BasePhone *)createPhone {
    return nil;
}

- (BaseWatch *)createWatch {
    
    return nil;
}

@end


@interface AppleFactory : BaseFactory

@end


@implementation AppleFactory
- (BasePhone *)createPhone {
    return [[ApplePhone alloc] init];
}

- (BaseWatch *)createWatch {
    return [[AppleWatch alloc] init];
}
@end

在下面的一步我们让apple和google厂分别可以生产手机和手表两种产品,这时候和上一步一样,有一个基础手机类和基础手表类:

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface BasePhone : NSObject
- (void) phoneCell;
@end

@implementation BasePhone
- (void)phoneCell {
    NSLog(@"This is a Phone");
}
@end

它的子类,除了继承并重写父类的方法,还添加了自己的方法:它的子类,除了继承并重写父类的方法,还添加了自己的方法:

@interface ApplePhone : BasePhone
- (void)applePhoneWays;
@end

@implementation ApplePhone
- (void)phoneCell {
    NSLog(@"This an apple phone");
}

- (void)applePhoneWays {
    NSLog(@"We can eat apple (phone)");
}
@end

其他类也和此相似
在ViewController中初始化,并执行各个方法:

    GooglePhone *googlePhone = (GooglePhone *)[googleFactory createPhone];
    //执行方法(1)
    [googlePhone phoneCell];
    [googlePhone googlePhoneWays];
    //确定商品(2)
    GoogleWatch *googleWatch = (GoogleWatch *)[googleFactory createWatch];
    //执行方法(2)
    [googleWatch watchCell];
    [googleWatch googleWatchWays];
    
    NSLog(@"-------------------------------------");
    
    //确定工厂
    BaseFactory *appleFactory = [FactoryManager factoryWithType:KApple];
    //确定商品(1)
    ApplePhone *applePhone = (ApplePhone *)[appleFactory createPhone];
    //执行方法(1)
    [applePhone phoneCell];
    [applePhone applePhoneWays];
    //确定商品(2)
    AppleWatch *appleWatch = (AppleWatch *)[appleFactory createWatch];
    //执行方法(2)
    [appleWatch watchCell];
    [appleWatch appleWatchWays];

运行的结果:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1608929.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

深入理解JAVA垃圾收集器CMS,G1工作流程原理 GC流程图 什么社会触发Minor GC?触发MinorGC过程。Full GC 过程。

java CMS&#xff0c;G1垃圾收集器工作流程原理浅析 JVM内存空间基础知识点&#xff08;基于JDk1.8&#xff09; 1.方法区&#xff1a;逻辑概念&#xff0c;元空间&#xff0c;方法区主要用于存储类的信息、常量池、方法数据、方法代码等。方法区逻辑上属于堆的一部分&#xf…

UE4_动画基础_根运动Root Motion

学习笔记&#xff0c;仅供参考&#xff01; 在游戏动画中&#xff0c;角色的碰撞胶囊体&#xff08;或其他形状&#xff09;通常由控制器驱动通过场景。然后来自该胶囊体的数据用于驱动动画。例如&#xff0c;如果胶囊体在向前移动&#xff0c;系统就会知道在角色上播放一个跑步…

C#语法知识之循环语句

5、循环语句 文章目录 1、while思考1 斐波那契数列思考2 判断一个数是否为质数思考3 找出100以内的质数 2、do...while3、for思考1 找水仙花数思考2 乘法表 1、while 1、作用 让代码重复去执行 2、语法相关 while(bool类型值){//当满足条件时&#xff0c;就会执行while语句…

深度学习每周学习总结P5(运动鞋识别)

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 | 接辅导、项目定制 –来自百度网盘超级会员V5的分享 目录 0. 总结1. 数据导入及处理部分2. 加载数据集3.模型构建部分3.1 模型构建3.2 公式推导 4. 设置超参…

深度强化学习开端——DQN算法求解车杆游戏

深度强化学习开端——DQN算法求解车杆游戏 DQN&#xff0c;即深度Q网络&#xff08;Deep Q-Network&#xff09;&#xff0c;是一种结合了深度学习和强化学习的算法&#xff0c;其主要用于解决序列决策问题&#xff0c;并且在许多复杂的决策任务中展现出了显著的效果。DQN算法…

C++:map和set的使用

一、关联式容器介绍 在学习map和set之前&#xff0c;我们接触到的容器有&#xff1a;vector、list、stack、queue、priority_queue、array&#xff0c;这些容器统称为序列式容器&#xff0c;因为其底层为线性序列的数据结构&#xff0c;里面存储的是元素本身。 关联式容器也是用…

【JavaEE多线程】线程中断 interrupt()

系列文章目录 &#x1f308;座右铭&#x1f308;&#xff1a;人的一生这么长、你凭什么用短短的几年去衡量自己的一生&#xff01; &#x1f495;个人主页:清灵白羽 漾情天殇_计算机底层原理,深度解析C,自顶向下看Java-CSDN博客 ❤️相关文章❤️&#xff1a;清灵白羽 漾情天…

用FRP配置toml文件搭建内网穿透

需求场景 1、一台外网可访问的有固定ip的云服务器&#xff0c;Ubuntu系统 2、一台外网无法访问的无固定ip的本地家用电脑&#xff0c;Ubuntu系统 需求&#xff1a;将云服务器搭建为一台内网穿透服务器&#xff0c;实现通过外网访问家用电脑&#xff08;网页&#xff09;的功能。…

Unity 中(提示框Tweet)

using UnityEngine; using UnityEngine.UI; using DG.Tweening; using System; public class Message : MonoBehaviour {public float dropDuration 0.5f; // 掉落持续时间public float persisterDuration 1f; // 持续显示时间public float dorpHeight;public static Message…

AWS账号注册以及Claude 3 模型使用教程!

哈喽哈喽大家好呀&#xff0c;伙伴们&#xff01;你听说了吗&#xff1f;最近AWS托管了大热模型&#xff1a;Claude 3 Opus&#xff01;想要一探究竟吗&#xff1f;那就赶紧来注册AWS账号吧&#xff01;别担心&#xff0c;现在注册还免费呢&#xff01;而且在AWS上还有更多的大…

macos知名的清理软件 cleanmymac和腾讯柠檬哪个好 cleanmymacx有必要买吗

MacOS是一款优秀的操作系统&#xff0c;但是随着使用时间的增加&#xff0c;它也会产生一些不必要的垃圾文件&#xff0c;占用磁盘空间和内存资源&#xff0c;影响系统的性能和稳定性。为了保持MacOS的清洁和高效&#xff0c;我们需要使用一些专业的清理软件来定期扫描和清除这…

DePIN 赛道黑马,peaq network 如何打造全新 Web3 物联网?

当 Web2 公司仍对用户数据和资料进行“中心化”的收集与控制时&#xff0c;我们虽享受到了物联网技术的便利&#xff0c;却依旧没有逃脱个人数据和价值所有权的剥夺。由此&#xff0c;Web3 技术开始深入物联网世界&#xff0c;智能家居、智能汽车、智能手机都成为重要发力点&am…

三大层次学习企业架构框架TOGAF

前言 对于一名架构师来讲&#xff0c;如果说编程语言是知识库层次中的入门石&#xff0c;那么企业架构框架则相当于知识库层次中的金字塔尖。如果想成长为企业级的架构师&#xff0c;企业架构框架是必须要攀登的高塔。 目前国内绝大多数企业采用TOGAF标准&#xff0c;因此我们…

XSS漏洞---类型+实战案例+防止

文章目录 目录 文章目录 一.XSS漏洞简介 二.XSS漏洞类型 三.实战案例 反射型XSS 存储型XSS 四.防护措施 一.XSS漏洞简介 XSS漏洞&#xff08;Cross-Site Scripting&#xff09;是一种常见的Web应用程序安全漏洞&#xff0c;它允许攻击者在受害者的浏览器中注入恶意脚本。当受…

记录一下flume中因为taildir_position.json因位置不对导致数据无法从kafka被采到hdfs上的问题

【背景说明】 我需要用flume将kafka上的数据采集到hdfs上&#xff0c;发现数据怎么到不了hdfs。 【问题排查】 1.kafka上已有相应的数据 2.我的flume配置文档&#xff08;没问题&#xff09;&#xff0c; 3.时间拦截器&#xff08;没问题&#xff09;&#xff0c; 4.JSONObje…

IDEA开启自动导包,自动删包

找到file----------->Settings选项 找到Editor-------->General------------>Auto Import选项 勾选两个选项&#xff0c;在点击Apply,在点击ok 最后就ok了

记录——FPGA的学习路线

文章目录 一、前言二、编程语言2.1 书籍2.2 刷题网站2.3 仿真工具 三、基础知识3.1 专业基础课3.2 fpga相关专业知识 四、开发工具五、动手实验 一、前言 也不是心血来潮想学习fpga了&#xff0c;而是祥哥还有我一个国科大的同学都在往fpga这个方向走 并且看过我之前文章的同…

基于SSH的通讯录管理系统

&#x1f449;文末查看项目功能视频演示获取源码sql脚本视频导入教程视频 1 、功能描述 基于SSH的通讯录管理系统拥有两种角色&#xff1a;管理员和用户 管理员&#xff1a;用户管理、公告管理、系别管理、班级管理、通讯信息管理等 用户&#xff1a;拥有管理员中的查看功能…

数据可视化(五):Pandas高级统计——函数映射、数据结构、分组聚合等问题解决,能否成为你的工作备用锦囊?

Tips&#xff1a;"分享是快乐的源泉&#x1f4a7;&#xff0c;在我的博客里&#xff0c;不仅有知识的海洋&#x1f30a;&#xff0c;还有满满的正能量加持&#x1f4aa;&#xff0c;快来和我一起分享这份快乐吧&#x1f60a;&#xff01; 喜欢我的博客的话&#xff0c;记得…

Vast+产品展厅 | Vastbase G100数据库是什么架构?(1)

Vastbase G100是海量数据融合了多年对各行业应用场景的深入理解&#xff0c;基于openGauss内核开发的企业级关系型数据库。 了解Vastbase G100的架构&#xff0c;可以帮助您确保数据库系统的高效、可靠和安全运行。 “Vast产品展厅”将分两期&#xff0c;为您详细讲解Vastbas…