用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 生成,作者有部分内容调整,如有任何不正确之处欢迎指正)

相关推荐
颜如玉2 小时前
🤲🏻🤲🏻🤲🏻临时重定向一定要能重定向🤲🏻🤲🏻🤲🏻
java·http·源码
2501_915918412 小时前
Web 前端可视化开发工具对比 低代码平台、可视化搭建工具、前端可视化编辑器与在线可视化开发环境的实战分析
前端·低代码·ios·小程序·uni-app·编辑器·iphone
2501_915106323 小时前
iOS 使用记录和能耗监控实战,如何查看电池电量消耗、App 使用时长与性能数据(uni-app 开发调试必备指南)
android·ios·小程序·uni-app·cocoa·iphone·webview
凉白开<--3 小时前
mardown-it 有序列表ios序号溢出解决办法
ios·vue
Digitally4 小时前
如何将 iPhone 备份到电脑/PC 的前 5 种方法
ios·电脑·iphone
Swift社区6 小时前
在企业内部分发 iOS App 时如何生成并使用 manifest.plist
macos·ios·cocoa
他们都不看好你,偏偏你最不争气9 小时前
【iOS】push 和 present
ios
2501_9160137412 小时前
HTTPS 抓包难点分析,从端口到工具的实战应对
网络协议·http·ios·小程序·https·uni-app·iphone
IT研究室13 小时前
大数据毕业设计选题推荐-基于大数据的国内旅游景点游客数据分析系统-Spark-Hadoop-Bigdata
大数据·hadoop·spark·毕业设计·源码·数据可视化·bigdata
2501_9159184114 小时前
uni-app 项目 iOS 上架效率优化 从工具选择到流程改进的实战经验
android·ios·小程序·uni-app·cocoa·iphone·webview