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

相关推荐
Digitally7 小时前
iPhone 恢复出厂设置是否会删除所有内容?
ios·iphone
2501_916007478 小时前
iPhone查看App日志和系统崩溃日志的完整实用指南
android·ios·小程序·https·uni-app·iphone·webview
Digitally9 小时前
如何将消息转移到新 iPhone
ios·iphone
mit6.8249 小时前
[Broken IOS] 配置&CLI | 终端用户界面TUI
c语言·ios·cocoa
2501_9159184111 小时前
iOS 抓不到包怎么办?全流程排查思路与替代引导
android·ios·小程序·https·uni-app·iphone·webview
wahkim21 小时前
iOS高级开发工程师面试——其他
ios
我现在不喜欢coding1 天前
混乱的scheme、.xcconfig、build Settings梳理的清清楚楚
ios·xcode
袋鱼不重1 天前
手把手搭建Vue轮子从0到1:4. Reactivity 模块的实现
前端·vue.js·源码
ls_qq_26708134701 天前
cocos打包web - ios设备息屏及前后台切换音频播放问题
前端·ios·音视频·cocos-creator
不爱说话郭德纲1 天前
别再花冤枉钱!手把手教你免费生成iOS证书(.p12) + 打包IPA(超详细)
前端·ios·app