用DeepSeek学源码-SDImageCodersManager 中的工厂模式解析

SDImageCodersManager 中的工厂模式解析

1. 工厂模式类型

SDImageCodersManager 应用了 抽象工厂模式(Abstract Factory Pattern) 的变体,更具体地属于 多态工厂模式(Pluggable Factory)

其核心特征:

  • 统一的抽象接口SDImageCoder 协议)定义编/解码能力。
  • 动态注册多组具体工厂(不同编/解码器的实现类)。
  • 运行时按需选择适配的工厂(根据图片数据格式)。

2. 工厂模式应用步骤

(1) 定义抽象产品接口(Protocol-Based)
  • 抽象产品接口SDImageCoder 协议

    声明所有编/解码器必须实现的核心方法:

    OBJECTIVEC 复制代码
    #import <UIKit/UIKit.h>
    
    NS_ASSUME_NONNULL_BEGIN
    
    @protocol SDImageCoder <NSObject>
    
    /// 判断是否能解码指定数据
    + (BOOL)canDecodeFromData:(NSData *)data;
    
    /// 解码数据生成图片
    - (nullable UIImage *)decodedImageWithData:(NSData *)data
                                      options:(nullable NSDictionary<SDImageCoderOptionKey, id> *)options;
    
    // 其他方法(编码、渐进式解码等)...
    
    @end
    
    NS_ASSUME_NONNULL_END

(2) 创建具体产品类(Concrete Product)
  • 具体产品实现 :多种编/解码器类

    针对不同图片格式实现协议,例如:

    OBJECTIVEC 复制代码
    // WebP 编/解码器
    
    #import "SDImageCoder.h"
    
    @interface SDImageWebPCoder : NSObject <SDImageCoder>
    
    @end
    
    #import "SDImageWebPCoder.h"
    
    @implementation SDImageWebPCoder
    
    + (BOOL)canDecodeFromData:(NSData *)data {
        // 检查 WebP Magic Number
        if (data.length < 12) return NO;
        uint32_t magic = 0;
        [data getBytes:&magic length:4];
        return magic == 0x52494646; // RIFF 标志位(WebP 文件头)
    }
    
    - (nullable UIImage *)decodedImageWithData:(NSData *)data
                                      options:(nullable NSDictionary<SDImageCoderOptionKey, id> *)options {
        // 实际调用 WebP 解码库(如 libwebp)的代码
        // ...
        return decodedImage;
    }
    
    @end
    
    
    
    // GIF 编/解码器
    #import <Foundation/Foundation.h>
    #import "SDImageCoder.h"
    
    @interface SDImageGIFCoder : NSObject <SDImageCoder>
    
    @end
    
    #import "SDImageGIFCoder.h"
    #import <ImageIO/ImageIO.h>  // 使用 ImageIO 框架解析 GIF
    
    @implementation SDImageGIFCoder
    
    #pragma mark - SDImageCoder Protocol
    
    + (BOOL)canDecodeFromData:(NSData *)data {
        // 检查 GIF Magic Number ("GIF8")
        if (data.length < 6) return NO;
        unsigned char magic[3];
        [data getBytes:magic length:3];
        return (magic[0] == 'G' && magic[1] == 'I' && magic[2] == 'F');
    }
    
    - (nullable UIImage *)decodedImageWithData:(NSData *)data
                                      options:(nullable NSDictionary<SDImageCoderOptionKey, id> *)options {
        // 使用 ImageIO 解析 GIF 数据
        CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL);
        if (!source) return nil;
    
        size_t frameCount = CGImageSourceGetCount(source);
        if (frameCount == 0) {
            CFRelease(source);
            return nil;
        }
    
        // 处理多帧 GIF 动画
        NSMutableArray<UIImage *> *frames = [NSMutableArray array];
        NSTimeInterval totalDuration = 0;
    
        for (size_t i = 0; i < frameCount; i++) {
            CGImageRef cgImage = CGImageSourceCreateImageAtIndex(source, i, NULL);

(3) 构建工厂管理者(Factory Manager)
  • 工厂管理类SDImageCodersManager

    统一管理所有注册的编/解码器实例,并根据数据类型选择对应工厂:

    OBJECTIVEC 复制代码
    #import <Foundation/Foundation.h>
    #import "SDImageCoder.h"
    
    @interface SDImageCodersManager : NSObject
    
    /// 单例入口
    @property (class, nonatomic, readonly) SDImageCodersManager *sharedManager;
    
    /// 添加编解码器(优先级越高越先被调用)
    - (void)addCoder:(id<SDImageCoder>)coder;
    
    /// 移除编解码器
    - (void)removeCoder:(id<SDImageCoder>)coder;
    
    /// 根据数据匹配可用的编解码器
    - (nullable id<SDImageCoder>)coderForData:(NSData *)data;
    
    @end
    
    #import "SDImageCodersManager.h"
    
    @interface SDImageCodersManager ()
    
    @property (nonatomic, strong) NSMutableArray<id<SDImageCoder>> *coders;
    
    @end
    
    @implementation SDImageCodersManager
    
    - (instancetype)init {
        if (self = [super init]) {
            // 注册常用解码器
            _imageCoders = [NSMutableArray arrayWithArray:@[[SDImageIOCoder sharedCoder], [SDImageGIFCoder sharedCoder], [SDImageAPNGCoder sharedCoder]]];
            SD_LOCK_INIT(_codersLock);
        }
        return self;
    }
    
    - (instancetype)init {
        self = [super init];
        if (self) {
            _coders = [NSMutableArray array];
        }
        return self;
    }
    //注册更多解码器,如:SDImageAWebPCoder、SDImageHEICCoder
    - (void)addCoder:(id<SDImageCoder>)coder {
        if (![self.coders containsObject:coder]) {
            [self.coders insertObject:coder atIndex:0]; // 插入到最前面(优先级最高)
        }
    }
    
    - (void)removeCoder:(id<SDImageCoder>)coder {
        [self.coders removeObject:coder];
    }
    
    - (nullable id<SDImageCoder>)coderForData:(NSData *)data {
        if (!data) return nil;
        for (id<SDImageCoder> coder in self.coders) {
            if ([coder.class canDecodeFromData:data]) {
                return coder;
            }
        }
        return nil;
    }
    
    @end

3. 模式结构对照表

工厂模式角色 SDImageCodersManager 中的实现
抽象工厂 (Abstract Factory) SDImageCoder 协议(定义工厂接口)
具体工厂 (Concrete Factory) 实现 SDImageCoder 的类(如 SDImageWebPCoder
工厂管理器 (Factory Manager) SDImageCodersManager
客户端 (Client) 使用 SDImageCodersManager 的调用方

4. 模式运行流程

  1. 初始化阶段

    • 注册编/解码器到 SDImageCodersManager

      OBJECTIVEC 复制代码
      // 注册自定义编解码器
      SDImageWebPCoder *webPCoder = [[SDImageWebPCoder alloc] init];
      [[SDImageCodersManager sharedManager] addCoder:webPCoder];
  2. 请求处理阶段

    • 客户端传递图片数据给 coder(for:)

      OBJECTIVEC 复制代码
      // 查询可用编解码器
      NSData *imageData = ...; // 输入图片二进制数据
      id<SDImageCoder> coder = [[SDImageCodersManager sharedManager] coderForData:imageData];
      UIImage *image = [coder decodedImageWithData:imageData options:nil];
    • 内部基于数据类型动态选择 SDImageWebPCoder 等具体实现。


5. 关键设计优势

  • 扩展性 :新增图片格式支持时,只需添加新的 SDImageCoder 实现类并注册,无需修改现有逻辑。
  • 解耦性:客户端无需关心具体编/解码器实现,仅依赖抽象协议。
  • 灵活性:可通过运行时动态调整注册的编/解码器(如禁用 GIF 支持)。

6. 差异说明:与经典工厂模式的对比

对比项 经典工厂模式 SDImageCodersManager
工厂类型 每个工厂类生产一种固定类型 多工厂共存,动态选择
工厂注册方式 编译时硬编码 运行时动态注册(addCoder/removeCoder
适用范围 产品类型预知且有限 未知/动态扩展的第三方格式支持

总结

SDImageCodersManager 将抽象工厂模式注册机制结合,形成一种灵活的插件化架构。通过协议定义标准化编/解码接口,允许第三方开发者无缝扩展新格式支持,完美契合图像处理场景的多格式需求。这种设计模式是 SDWebImage 能长期保持 iOS 生态领跑地位的重要原因之一。

(ps: 以上大部分内容使用 DeepSeek R 生成,作者有部分内容调整,如有任何不正确之处欢迎指正)

相关推荐
Digitally4 小时前
如何在没有 iTunes 的情况下备份 iPhone
ios·iphone
刘_小_二5 小时前
iOS用Xib 之三等分以及多等分思路
ios
season_zhu6 小时前
Swift:优雅又强大的语法糖——Then库
ios·架构·swift
I烟雨云渊T15 小时前
iOS 门店营收表格功能的实现
ios
明月看潮生21 小时前
青少年编程与数学 01-011 系统软件简介 07 iOS操作系统
ios·青少年编程·操作系统·系统软件
90后的晨仔1 天前
RxSwift 框架解析
前端·ios
可爱小仙子1 天前
ios苹果系统,js 滑动屏幕、锚定无效
前端·javascript·ios
未来猫咪花1 天前
# Flutter状态管理对比:view_model vs Riverpod
flutter·ios·android studio
咕噜企业签名分发-淼淼1 天前
开发源码搭建一码双端应用分发平台教程:逐步分析注意事项
android·ios
键盘敲没电2 天前
【IOS】GCD学习
学习·ios·objective-c·xcode