直接new云客户端导致切换困难,因业务逻辑与SDK强耦合;工厂模式通过统一接口、配置驱动的工厂类和适配器层封装差异,实现“秒切”。

为什么直接 new 云客户端会导致切换困难
硬编码 new AliyunOssClient() 或 new AwsS3Client() 会让业务逻辑和具体 SDK 强耦合。一旦要从 OSS 切到 S3,就得全局搜 new、改构造参数、修签名逻辑、调兼容层——不是“秒切”,是“停服改代码”。工厂模式的核心作用,就是把「实例化谁」这个决策,从业务代码里拎出来,集中控制。
定义统一接口:先写 CloudStorageInterface
不提前约定行为,工厂产出的对象就无法被业务安全调用。必须抽象出最小可用契约,比如上传、下载、生成预签名 URL:
interface CloudStorageInterface
{
public function upload(string $key, string $content): bool;
public function download(string $key): ?string;
public function getSignedUrl(string $key, int $expires = 3600): string;
}
注意两点:
• getSignedUrl() 返回 string 而非 UrlObject,避免引入 SDK 特有类型
• 不暴露 bucket、region 等配置细节,由工厂内部处理
工厂类怎么根据配置决定返回哪个实现
工厂本身不负责初始化 SDK,只做路由。关键在「配置驱动」而非「if-else 硬判断」:
- 读取配置项
STORAGE_DRIVER(值为'oss'或's3') - 检查对应实现类是否已加载(可用
class_exists()防错) - 传入标准化的配置数组(如
['endpoint' => '...', 'access_key' => '...']),而非原始 SDK 参数结构 - 绝不缓存实例——不同 bucket 可能需不同 client,工厂应每次返回新实例,或交由 DI 容器管理生命周期
示例节选:
class CloudStorageFactory
{
public static function make(string $driver, array $config): CloudStorageInterface
{
return match ($driver) {
'oss' => new AliyunOssAdapter($config),
's3' => new AwsS3Adapter($config),
default => throw new InvalidArgumentException("Unsupported driver: {$driver}")
};
}
}
OSS 与 S3 实现里最常踩的坑
接口一致不等于行为一致。以下差异不处理,切过去立刻报错:
-
AliyunOssAdapter的upload()必须把$key视为完整路径(含目录),而AwsS3Adapter默认也如此,但某些旧版 S3 SDK 会自动 trim 开头/—— 统一在适配器内 normalize$key = ltrim($key, '/') - S3 的
getSignedUrl()依赖Command对象和Presigner,OSS 则用Signer::signUrl();二者过期时间单位都是秒,但 OSS 的$expires参数名可能叫$timeout—— 适配器内统一转译,对外隐藏 - OSS 的 endpoint 格式是
https://oss-cn-hangzhou.aliyuncs.com,S3 是https://s3.us-east-1.amazonaws.com;若配置里混用区域名(如cn-hangzhou)和区域 ID(us-east-1),工厂需做映射或抛明确错误
真正“秒切”的前提是:业务代码只依赖 CloudStorageInterface,且所有适配器对同一输入给出语义一致的输出。配置改一行,驱动换一个,其余不动——但前提是每个适配器都认真处理了这些细节。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











