factory method design pattern
工厂方法模式的概念、工厂方法模式的结构、工厂方法模式的优缺点、工厂方法模式的使用场景、工厂方法模式的实现示例、工厂方法模式的源码分析
1、工厂方法的概念
工厂方法模式,及简单工厂模式的升级版,其抽象了对象的创建,将对象的具体创建延迟到了其子类中。这样,当有新产品加入时,不用再修改已有的工厂类,只需要增加新产品的实现和新产品对应工厂的实现即刻。
2、工厂方法的结构
- 抽象产品:定义产品的行为。
- 具体产品:实现抽象产品,使产品具像化。
- 抽象工厂:定义生产产品的行为。
- 具体工厂:实现抽象工厂,来创建一个具体产品的对象实例。其与具体产品是一对一的关系。
3、工厂方法的优缺点
- 优点:
- 用户只需要知道具体的产品工厂即刻得到产品,无需了解产品的创建过程。
- 新增产品时只需要新增具体产品类和其对应的具体工厂类即刻,无需对已有的工厂类进行修改,符合开闭原则的要求。
- 缺点:
- 当系统中产品过多时,会使系统过于复杂。
4、工厂方法的使用场景
- 需要创建对象的地方。
- 需要灵活的、可扩展的框架。
- 针对同种类不同属性的操作,如数据库中的 mysql、oracle 等。
5、工厂方法的实现示例
抽象产品:
public interface Product {
/**
* 定义产品行为
*/
void behavior();
}
具体产品一:
public class OneProduct implements Product {
@Override
public void behavior() {
System.out.println("我是产品一");
}
}
具体产品二:
public class TwoProduct implements Product {
@Override
public void behavior() {
System.out.println("我是产品二");
}
}
抽象工厂:
public interface Factory {
/**
* 生产
* @return
*/
Product product();
}
具体工厂一:
public class OneFactory implements Factory {
@Override
public Product product() {
return new OneProduct();
}
}
具体工厂二:
public class TwoFactory implements Factory {
@Override
public Product product() {
return new TwoProduct();
}
}
测试:
public class FactoryMethodTest {
public static void main(String[] args) {
Factory oneFactory = new OneFactory();
Factory twoFactory = new TwoFactory();
Product oneProduct = oneFactory.product();
Product twoProduct = twoFactory.product();
oneProduct.behavior();
twoProduct.behavior();
}
}
测试结果:
我是产品一
我是产品二
6、工厂方法的源码分析
slf4j 中的 Logger logger = LoggerFactory.getLogger(FactoryMethodTest.class) 就是工厂方法模式的实现体现。其中 Logger 接口就是抽象产品接口,具体产品类如 EventRecodingLogger、SubstituteLogger 等;ILoggerFactory 抽象类就是抽象工厂,SubstituteLoggerFactory 等就是具体工厂类。
另外 spring 中的 FactoryBean、java.util.concurrent 中的 ThreadFactory、mybatis 中的 SqlSessionFactory 等就是工厂方法模式。
public interface Logger {
...
}
public interface ILoggerFactory {
/**
* Return an appropriate {@link Logger} instance as specified by the
* <code>name</code> parameter.
*
* <p>If the name parameter is equal to {@link Logger#ROOT_LOGGER_NAME}, that is
* the string value "ROOT" (case insensitive), then the root logger of the
* underlying logging system is returned.
*
* <p>Null-valued name arguments are considered invalid.
*
* <p>Certain extremely simple logging systems, e.g. NOP, may always
* return the same logger instance regardless of the requested name.
*
* @param name the name of the Logger to return
* @return a Logger instance
*/
public Logger getLogger(String name);
}
public class SubstituteLoggerFactory implements ILoggerFactory {
...
public synchronized Logger getLogger(String name) {
SubstituteLogger logger = (SubstituteLogger)this.loggers.get(name);
if (logger == null) {
logger = new SubstituteLogger(name, this.eventQueue, this.postInitialization);
this.loggers.put(name, logger);
}
return logger;
}
...
}