007工厂模式(简单工厂、工厂方法、抽象工厂)

文章详细介绍了工厂模式的三种主要类型:简单工厂、工厂方法和抽象工厂。通过代码示例展示了它们的使用场景和区别,强调了简单工厂在实际项目中的常见应用以及如何通过IOC注入和反射来优化工厂方法的实现。同时,提到了抽象工厂在处理多维度对象创建时的作用。
摘要由CSDN通过智能技术生成

一般情况下,工厂模式分为 三种

  • 简单工厂
  • 工厂方法
  • 抽象工厂

在我看来,简单工厂其实是工厂方法的一种特例,但它在我们项目开发中基本上必须使用,单独抽出来。
工厂方法 在spring、mybatis等源码中基本上都存在 ,项目中也会使用,也是必须掌握的,抽象工厂相对用的比较少,这里就不多说了,感兴趣的可以自行研究

简单工厂

先演示代码,基本两种情况,第一种每次new一个对象,第二种缓存对象,直接获取

 
// 第一种
public class RuleConfigParserFactory {
  public static IRuleConfigParser createParser(String configFormat) {
    IRuleConfigParser parser = null;
    if ("json".equalsIgnoreCase(configFormat)) {
      parser = new JsonRuleConfigParser();
    } else if ("xml".equalsIgnoreCase(configFormat)) {
      parser = new XmlRuleConfigParser();
    } else if ("yaml".equalsIgnoreCase(configFormat)) {
      parser = new YamlRuleConfigParser();
    } else if ("properties".equalsIgnoreCase(configFormat)) {
      parser = new PropertiesRuleConfigParser();
    }
    return parser;
  }
}

//第二种

public class RuleConfigParserFactory {
  private static final Map<String, RuleConfigParser> cachedParsers = new HashMap<>();

  static {
    cachedParsers.put("json", new JsonRuleConfigParser());
    cachedParsers.put("xml", new XmlRuleConfigParser());
    cachedParsers.put("yaml", new YamlRuleConfigParser());
    cachedParsers.put("properties", new PropertiesRuleConfigParser());
  }

  public static IRuleConfigParser createParser(String configFormat) {
    if (configFormat == null || configFormat.isEmpty()) {
      return null;//返回null还是IllegalArgumentException全凭你自己说了算
    }
    IRuleConfigParser parser = cachedParsers.get(configFormat.toLowerCase());
    return parser;
  }
}

对于这两种情况,如果我们要添加新的parser,只有要修改下 代码,稍微不符合开闭原则,
对应 if 判断,如果代码比较简单,也没什么问题,可读性、可修改都很灵活

工厂方法

那么工厂方法和简单工厂区别是什么呢, 其实我们推演下,把刚才的if 分支去掉,使用多态的方式替代掉

这里区别是什么
重点是对象的创建是否复杂, 对应创建型的设计模式,主要是用来创建对象的,

  • 如果对象的创建不复杂,比如new 就可以了,我们只有使用简单工厂就可以了,
  • 如果对象创建比较复杂,涉及引用其他对象,
  • 或者判断逻辑,我们把对象的创建拆分开,单独一个类,隐藏创建的复杂逻辑,这里就可以使用工厂方法了

public interface IRuleConfigParserFactory {
  IRuleConfigParser createParser();
}

public class JsonRuleConfigParserFactory implements IRuleConfigParserFactory {
  @Override
  public IRuleConfigParser createParser() {
    return new JsonRuleConfigParser();
  }
}

public class XmlRuleConfigParserFactory implements IRuleConfigParserFactory {
  @Override
  public IRuleConfigParser createParser() {
    return new XmlRuleConfigParser();
  }
}

public class YamlRuleConfigParserFactory implements IRuleConfigParserFactory {
  @Override
  public IRuleConfigParser createParser() {
    return new YamlRuleConfigParser();
  }
}

public class PropertiesRuleConfigParserFactory implements IRuleConfigParserFactory {
  @Override
  public IRuleConfigParser createParser() {
    return new PropertiesRuleConfigParser();
  }
}

这个怎么使用呢,这里又绕回去了,我们需要再创建一个类似简单工厂的形式 ,它复杂创建工厂的工厂


 //因为工厂类只包含方法,不包含成员变量,完全可以复用,
//不需要每次都创建新的工厂类对象,所以,简单工厂模式的第二种实现思路更加合适。
public class RuleConfigParserFactoryMap { //工厂的工厂
  private static final Map<String, IRuleConfigParserFactory> cachedFactories = new HashMap<>();

  static {
    cachedFactories.put("json", new JsonRuleConfigParserFactory());
    cachedFactories.put("xml", new XmlRuleConfigParserFactory());
    cachedFactories.put("yaml", new YamlRuleConfigParserFactory());
    cachedFactories.put("properties", new PropertiesRuleConfigParserFactory());
  }

  public static IRuleConfigParserFactory getParserFactory(String type) {
    if (type == null || type.isEmpty()) {
      return null;
    }
    IRuleConfigParserFactory parserFactory = cachedFactories.get(type.toLowerCase());
    return parserFactory;
  }
}

对应我们项目中,哪些会用到工厂方法呢

  • Java 中的 Calendar、DateFormat 类。
  • valueOf() 返回与入参相等的对象 例如 Integer.valueOf()
  • getInstance() 返回单例对象 例如 Calendar.getInstance()
  • newInstance() 每次调用时返回新的对象 例如 HelloWorld.class.getConstructor().newInstance()
  • 在反射中的工厂方法 例如 XXX.class.getField(String name) 返回成员

抽象工厂

这里简单说一下,比较抽象工厂我们不常使用,比如在代码实例中,规则配置解析,会根据 josn、xml、yaml等分类,创建不同的工厂,但是如果类有2种划分方式,比如我们 按照配置文件格式分类,也按照解析对象是rule配置还是系统配置分类,就会有8种方式,产生类爆炸

 
针对规则配置的解析器:基于接口IRuleConfigParser
JsonRuleConfigParser
XmlRuleConfigParser
YamlRuleConfigParser
PropertiesRuleConfigParser

针对系统配置的解析器:基于接口ISystemConfigParser
JsonSystemConfigParser
XmlSystemConfigParser
YamlSystemConfigParser
PropertiesSystemConfigParser

怎么解决呢 我们可以让一个工厂负责创建多个不同类型的对象(IRuleConfigParser、ISystemConfigParser 等),而不是只创建一种 parser 对象

 
public interface IConfigParserFactory {
  IRuleConfigParser createRuleParser();
  ISystemConfigParser createSystemParser();
  //此处可以扩展新的parser类型,比如IBizConfigParser
}

public class JsonConfigParserFactory implements IConfigParserFactory {
  @Override
  public IRuleConfigParser createRuleParser() {
    return new JsonRuleConfigParser();
  }

  @Override
  public ISystemConfigParser createSystemParser() {
    return new JsonSystemConfigParser();
  }
}

public class XmlConfigParserFactory implements IConfigParserFactory {
  @Override
  public IRuleConfigParser createRuleParser() {
    return new XmlRuleConfigParser();
  }

  @Override
  public ISystemConfigParser createSystemParser() {
    return new XmlSystemConfigParser();
  }
}

// 省略YamlConfigParserFactory和PropertiesConfigParserFactory代码

这个可以看出了,确实不太常用

工厂方法的改良

实际上 ,对于简单工厂,我们代码中还会经常使用,
对于工厂方法,传统的还是太麻烦了, 现在我们利用 spring容器,可以这样使用

一、利用 ioc注入

将不同的RuleConfigParser实现按照约定格式指定beanName注入,
比方说@Component(“XmlRuleConfigParser”),取的时候applicationContext.getBean(typeSuffix+RuleConfigParser)即可,拓展的话,自己写一个xxRuleConfigParser,就注入进去了,也不需要在map容器新增。 整个工厂方法就是

public RuleConfigParser getInstance(suffix){
    return InstanceLocator.getBean(suffix+"RuleConfigParser");
}

二、利用反射

下面是我借助于chatgpt 生成的代码

可以将工厂类的配置信息存储在属性文件中,然后使用Java反射机制动态创建工厂对象。具体实现步骤如下:
可以将工厂类的配置信息存储在属性文件中,然后使用Java反射机制动态创建工厂对象。具体实现步骤如下:

  1. 创建配置文件factory.properties,用于存储工厂类的配置信息,格式如下所示:
parser.factory.json=com.example.factory.JsonRuleConfigParserFactory
parser.factory.xml=com.example.factory.XmlRuleConfigParserFactory
parser.factory.yaml=com.example.factory.YamlRuleConfigParserFactory
parser.factory.properties=com.example.factory.PropertiesRuleConfigParserFactory

其中,parser.factory.json表示对应的解析器类型,com.example.factory.JsonRuleConfigParserFactory表示该类型对应的工厂类的全限定名称。

  1. 定义一个工厂类RuleConfigParserFactory,该类读取配置文件中的信息,并使用反射机制动态创建相应的工厂对象,代码如下所示:
public class RuleConfigParserFactory {
    private static final Map<String, IRuleConfigParserFactory> cachedFactories = new HashMap<>();

    static {
        Properties props = new Properties();
        InputStream in = null;
 
            in = RuleConfigParserFactory.class.getResourceAsStream("/factory.properties");
            props.load(in);
            for (Object name : props.keySet()) {
                String type = (String) name;
                String className = props.getProperty(type);
                Class<?> clazz = Class.forName(className);
                IRuleConfigParserFactory factory = (IRuleConfigParserFactory) clazz.newInstance();
                cachedFactories.put(type, factory);
            }
      
    }

    public static IRuleConfigParserFactory getParserFactory(String type) {
        if (type == null || type.isEmpty()) {
            return null;
        }
        IRuleConfigParserFactory parserFactory = cachedFactories.get(type.toLowerCase());
        return parserFactory;
    }
}

该类通过读取配置文件,在静态代码块中反射创建工厂对象,并将其缓存起来。

  1. 客户端调用工厂的getParserFactory(type)方法来获取相应类型的规则配置解析器对象。例如:
IRuleConfigParserFactory factory = RuleConfigParserFactory.getParserFactory("json");
IRuleConfigParser parser = factory.createParser();

该代码可以根据解析器类型来创建相应类型的工厂对象,并进一步使用工厂对象创建解析器对象。
使用反射机制来实现工厂的获取可以提高代码的灵活性和可维护性,并且避免了手动创建工厂对象的麻烦。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值