定义
- 简单工厂:由一个工厂对象决定创建出产品的实例。
- 工厂方法:定义一个用于创建对象的接口,让使用者决定实例化哪一个类。工厂方法使一个类的实例化延迟到其使用者。
- 抽象工厂:提供一个创建一系列相关或者相互依赖对象的接口,而无需指定他们具体实现类。
使用场景
- 简单工厂模式将对象的创建和对象的使用进行了分离,屏蔽了中间具体的产品类,让对象的使用者不需要知道对象的创建细节。比如线程池的创建,我们不需要知道
ThreadPoolExecutor
创建所需的参数,我们只需要直接使用ExecutorService
接口就可以。
public class Executors {
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
...
}
- 工厂方法也是将将对象的创建和对象的使用进行了分离,但是在使用的时候通常是将工厂接口作为参数传入。如
ThreadPoolExecutor
中的ThreadFactory
参数,该参数可以定制线程池中线程的名字,优先级等属性。
public class ThreadPoolExecutor extends AbstractExecutorService {
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
}
...
}
实现方式
工厂方法实现的代码
package com.fzsyw.test;
/**
* 产品抽象类
*/
public abstract class Product {
public abstract void method();
}
/**
* 具体A产品
*/
public class ConcreteProductA extends Product {
@Override
public void method() {
System.out.println("产品A");
}
}
/**
* 具体B产品
*/
public class ConcreteProductB extends Product {
@Override
public void method() {
System.out.println("产品B");
}
}
/**
* 工厂抽象类
*/
public abstract class Factory {
public abstract Product createProduct();
}
/**
* 具体工厂
*/
public class ConcreteFactory extends Factory {
@Override
public Product createProduct() {
return new ConcreteProductA();
}
}
/**
* 客户端使用
*/
public class Client {
public static void main(String[] args) {
Factory factory = new ConcreteFactory();
Product product = factory.createProduct();
product.method();
}
}
public abstract class Factory {
public abstract <T extends Product> T createProduct(String name);
}
/**
* 通过反射的方式
*/
public class ConcreteFactory extends Factory {
@Override
public <T extends Product> T createProduct(String name) {
Product product = null;
try {
product= (Product) Class.forName(name).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return (T) product;
}
}
public class Client {
public static void main(String[] args) {
Factory factory = new ConcreteFactory();
Product product = factory.createProduct("com.fzsyw.test.ConcreteProductB");
product.method();
}
}
/**
* 实际中可能用ApplicationContext或者BeanFactory来获取
*/
public class ConcreteFactory extends Factory {
@Autowired
private ApplicationContext applicationContext;
@Override
public <T extends Product> T createProduct(String name) {
return applicationContext.getBean(name, T.class);
}
}
扩展与思考
- 工厂方法可以说是对简单工厂的升级。简单工厂适用于只有固定的几个产品,不利于扩展,它只能通过在简单工厂中添加新的方法来生产新的产品,不符合开闭原则。工厂方法则是添加了一个工厂的接口,也就是每多一个产品,就要新增一个工厂来进行维护,虽然增加扩展性,但是也带来了复杂性。
- 工厂模式有很多变种,如Spring的
BeanFactory
本身就是产生Bean的工厂,但是它结合了单例模式,默认情况产生的Bean都是单例的。 JDK
中NumberFormat
也用到了简单的工厂模式,但是做了改动,它即是工厂,也是产品(提供了产品的公共方法和抽象方法,抽象方法就由子类实现)。这种模式下,抽象工厂类可以提供通用的代码和统一的访问接口,而具体的子类可以将类的public去掉,让抽象工厂类成为唯一的对外接口。
public abstract class NumberFormat extends Format {
public final static NumberFormat getInstance() {
return getInstance(Locale.getDefault(Locale.Category.FORMAT), NUMBERSTYLE);
}
public static NumberFormat getInstance(Locale inLocale) {
return getInstance(inLocale, NUMBERSTYLE);
}
/**
* 通用的接口,不用子类实现
*/
public final String format(long number) {
return format(number, new StringBuffer(),
DontCareFieldPosition.INSTANCE).toString();
}
/**
* 特定接口,由子类实现
*/
public abstract StringBuffer format(double number,
StringBuffer toAppendTo,
FieldPosition pos);
...
}