定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method使一个类的实例化延迟到其子类。
工厂方法的目的是使得创建对象和使用对象是分离的,并且客户端总是引用抽象工厂和抽象产品:
┌─────────────┐ ┌─────────────┐ │ Product │ │ Factory │ └─────────────┘ └─────────────┘ ▲ ▲ │ │ ┌─────────────┐ ┌─────────────┐ │ ProductImpl │<─ ─ ─│ FactoryImpl │ └─────────────┘ └─────────────┘
工厂接口:
public interface NumberFactory { Number parse(String s); }
工厂实现类:
public class NumberFactoryImpl implements NumberFactory { public Number parse(String s) { return new BigDecimal(s); } }
产品接口是Number
,NumberFactoryImpl
返回的实际产品是BigDecimal
客户端如何创建NumberFactoryImpl
呢?通常我们会在接口Factory
中定义一个静态方法getFactory()
来返回真正的子类:
public interface NumberFactory { // 创建方法: Number parse(String s); // 获取工厂实例: static NumberFactory getFactory() { return impl; } //获取实现类 static NumberFactory impl = new NumberFactoryImpl(); }
在客户端中,我们只需要和工厂接口NumberFactory
以及抽象产品Number
打交道:
NumberFactory factory = NumberFactory.getFactory(); Number result = factory.parse("123.456");
调用方可以完全忽略真正的工厂NumberFactoryImpl
和实际的产品BigDecimal
,这样做的好处是允许创建产品的代码独立地变换,而不会影响到调用方。
静态工厂方法广泛地应用在Java标准库中
Integer n = Integer.valueOf(100); #Integer n = new Integer(100);
Integer
既是产品又是静态工厂。它提供了静态方法valueOf()
来创建Integer
。那么这种方式和直接写new Integer(100)
有何区别呢?我们观察valueOf()
方法:
public final class Integer { public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); } ... }
valueOf()
内部可能会使用new
创建一个新的Integer
实例,但也可能直接返回一个缓存的Integer
实例。对于调用方来说,没必要知道Integer
创建的细节。
如果调用方直接使用Integer n = new Integer(100)
,那么就失去了使用缓存优化的可能性。
工厂方法可以隐藏创建产品的细节,且不一定每次都会真正创建产品,完全可以返回缓存的产品,从而提升速度并减少内存消耗。
提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
抽象工厂模式和工厂方法不太一样,它要解决的问题比较复杂,不但工厂是抽象的,产品是抽象的,而且有多个产品需要创建,因此,这个抽象工厂会对应到多个实际工厂,每个实际工厂负责创建多个实际产品:
┌────────┐ ─ >│ProductA│ ┌────────┐ ┌─────────┐ │ └────────┘ │ Client │─ ─>│ Factory │─ ─ └────────┘ └─────────┘ │ ┌────────┐ ▲ ─ >│ProductB│ ┌───────┴───────┐ └────────┘ │ │ ┌─────────┐ ┌─────────┐ │Factory1 │ │Factory2 │ └─────────┘ └─────────┘ │ ┌─────────┐ │ ┌─────────┐ ─ >│ProductA1│ ─ >│ProductA2│ │ └─────────┘ │ └─────────┘ ┌─────────┐ ┌─────────┐ └ ─>│ProductB1│ └ ─>│ProductB2│ └─────────┘ └─────────┘