我们都知道在现实生活中,原始社会自给自足(没有工厂),农耕社会小作坊(简单工厂,民间酒坊),工业革命流水线(工厂方法,自产自销),现代产业链代工厂(抽象工厂,富士康)。我们的项目代码同样是由简至繁一步一步迭代而来的,但对于调用者来说,却越来越简单。在日常开发中,凡是需要生成复杂对象的地方,都可以尝试考虑使用工厂模式来代替。
工厂模式,按照实际业务场景进行划分,有3种不同的实现方式,分别是简单工厂模式
,工厂方法模式
和抽象工厂模式
。
简单工厂模式
简单工厂模式(Simple Factory Pattern)又叫做静态工厂方法模式(Static Factory Method Pattern),属于创建型设计模式。简单工厂模式不在GoF23种设计模式之中。
简单工厂模式将定义一个工厂类,根据参数的不同返回不同类的实例,被创建的实例又都有共同的父类。
设计思想
简单工厂:负责实现创建所有实例的内部逻辑,工厂类的创建产品类的方法可以被外部直接调用创建所需的产品对象
抽象产品:简单工厂创建的所有对象的父类,负责描述所有实例共有特点的公共接口
具体产品:简单工厂模式的创建目标
在简单工厂模式中,客户端通过工厂类来创建一个产品类的实例,无须直接使用new关键字来创建对象,它是工厂模式家族中最简单的一员。
伪代码
抽象产品
//抽象产品
public interface IButton{
//抽象业务方法
void methodSome();
}
//具体产品
public class WhiteButton implements IButton{
//实现抽象业务方法
public void methodSome(){
...
}
}
public class RedButton implements IButton{
//实现抽象业务方法
public void methodSome(){
...
}
}
//简单工厂
public class SimpleFactory{
public static IButton makeButton(String arg){
switch(arg) {
case "red":return new RedButton();
case "white":return new WhiteButton();
}
return null;
}
}
//客户端
class Client{
public static void main(String[] args){
IButton button = SimpleFactory.makeButton("red");
}
}
优化
如何又要增加新的具体产品,那么势必会修改工厂中的创建方法,不符合开闭原则。因此,可以使用反射技术继续对简单工厂模式进行优化。
//简单工厂
public class SimpleFactory{
public static IButton makeButton(Class<? extends IButton> clazz){
try{
if(null != clazz){
return clazz.newInstance();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
//客户端
public static void main(String[] args){
IButton button = SimpleFactory.makeButton(RedButton.class);
}
应用
在大家经常使用的Logback中,可以看到LoggerFactory中有多个重载的方法getLogger()
云服务器:互联网上有许多云服务器,例如阿里云、七牛云、腾讯云服务器。在renren-fast开源框架中,作者用简单工厂模式实现了不同用户可以选择自己喜爱的云服务器的功能。
//OSS简单工厂类
public final class OSSFactory {
private static SysConfigService sysConfigService;
static {
OSSFactory.sysConfigService = (SysConfigService) SpringContextUtils.getBean("sysConfigService");
}
public static CloudStorageService build(){
//获取云存储配置信息
CloudStorageConfig config = sysConfigService.getConfigObject(ConfigConstant.CLOUD_STORAGE_CONFIG_KEY, CloudStorageConfig.class);
//通过参数得到不同的云服务器
if(config.getType() == Constant.CloudService.QINIU.getValue()){
return new QiniuCloudStorageService(config);
}else if(config.getType() == Constant.CloudService.ALIYUN.getValue()){
return new AliyunCloudStorageService(config);
}else if(config.getType() == Constant.CloudService.QCLOUD.getValue()){
return new QcloudCloudStorageService(config);
}
return null;
}
}
//抽象产品(云服务)
public abstract class CloudStorageService {
/** 云存储配置信息 */
CloudStorageConfig config;
/**
* 文件路径
*/
public String getPath(String prefix, String suffix) {
//生成uuid
String uuid = UUID.randomUUID().toString().replaceAll("-", "");
//文件路径
String path = DateUtils.format(new Date(), "yyyyMMdd") + "/" + uuid;
if(StringUtils.isNotBlank(prefix)){
path = prefix + "/" + path;
}
return path + suffix;
}
/**
* 文件上传
*/
public abstract String upload(byte[] data, String path);
/**
* 文件上传
*/
public abstract String uploadSuffix(byte[] data, String suffix);
/**
* 文件上传
*/
public abstract String upload(InputStream inputStream, String path);
/**
* 文件上传
*/
public abstract String uploadSuffix(InputStream inputStream, String suffix);
}
三个具体的云服务器继承了抽象产品,实现自己的业务方法。这里只给出阿里云服务。
/**
* 具体产品:阿里云存储
*/
public class AliyunCloudStorageService extends CloudStorageService {
private OSSClient client;
public AliyunCloudStorageService(CloudStorageConfig config){
this.config = config;
//初始化
init();
}
private void init(){
client = new OSSClient(config.getAliyunEndPoint(), config.getAliyunAccessKeyId(),
config.getAliyunAccessKeySecret());
}
@Override
public String upload(byte[] data, String path) {
return upload(new ByteArrayInputStream(data), path);
}
@Override
public String upload(InputStream inputStream, String path) {
try {
client.putObject(config.getAliyunBucketName(), path, inputStream);
} catch (Exception e){
throw new RRException("上传文件失败,请检查配置信息", e);
}
return config.getAliyunDomain() + "/" + path;
}
@Override
public String uploadSuffix(byte[] data, String suffix) {
return upload(data, getPath(config.getAliyunPrefix(), suffix));
}
@Override
public String uploadSuffix(InputStream inputStream, String suffix) {
return upload(inputStream, getPath(config.getAliyunPrefix(), suffix));
}
}