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

相关推荐
Mamong1 小时前
Metal 学习笔记三:渲染管线
ios·swift·metal
yimeixiaolangzai6 小时前
django基于python 语言的酒店推荐系统
python·mysql·django·源码·课程设计
xinyu3917 小时前
iOS Framework代码中加载图片资源
macos·ios·cocoa
键盘敲没电7 小时前
【iOS】小蓝书学习(四)
学习·ios·cocoa
键盘敲没电15 小时前
【iOS】小蓝书学习(二)
学习·ios·cocoa
黄毛火烧雪下1 天前
将 iOS 项目打包并运行到真实的 iPhone 设备
ios·iphone
后端常规开发人员2 天前
iOS手机App爬虫- (1) Mac安装Appium真机运行环境
爬虫·ios·appium
DeMonnnnnn2 天前
Flutter-升级Xcode后构建iOS报错
flutter·ios·xcode
明远湖之鱼2 天前
关于我在 iOS 开发中用 Swift 实现的两个交互效果
前端·ios·swift