一般理解,工厂就是批量生产某种东西的地方,相对的,Java中的工厂模式就是创建对象的地方,是创建类模式中的一种。它解决的主要问题就是将“对象的创建逻辑与操作对象的业务逻辑分离解耦”,分别在不同的地方实现,而不是混杂在一起,目的是提供更清晰更容易扩展的代码。
工厂模式有简单工厂、方法工厂、抽象工厂三类。
1、简单工厂模式
简单工厂模式适用于生产的“产品”种类很少,只需要提供一种工厂的场景。假设有如下场景,首先有一个关于面条的接口:
// 面条接口
interface Noodle {
public void say();
}
现在有两种具体的面条:
// 拉面
class HandPulledNoodles implements Noodles {
@Override
public void say() {
System.out.println("I am hand-pulled noodles");
}
}
// 方便面
class InstantNoodles implements Noodles {
@Override
public void say() {
System.out.println("I am instant noodles");
}
}
接下来根据程序的输入条件创建不同的面条,在不使用工厂模式的情况下,全部代码如下:
// 面条接口
interface Noodles {
public void say();
}
// 拉面
class HandPulledNoodles implements Noodles {
@Override
public void say() {
System.out.println("I am hand-pulled noodles");
}
}
// 方便面
class InstantNoodles implements Noodles {
@Override
public void say() {
System.out.println("I am instant noodles");
}
}
public class SimpleFactory {
public static void main(String[] args) {
Noodles n = null;
// 创建逻辑
if (args[0].equalsIgnoreCase("HandPulled")) {
n = new HandPulledNoodles();
} else if (args[0].equalsIgnoreCase("Instant")) {
n = new InstantNoodles();
}
// 业务逻辑
if (n != null) {
n.say();
} else {
System.out.println("Parameter error");
}
}
}
可以看到面条的创建逻辑与业务逻辑混合在一起,如果想新增加一种新面条,如意大利面,则需要修改main方法。接下来使用简单工厂模式,将创建逻辑与业务逻辑分离,代码如下:
// 面条接口
interface Noodles {
public void say();
}
// 拉面
class HandPulledNoodles implements Noodles {
@Override
public void say() {
System.out.println("I am hand-pulled noodles");
}
}
// 方便面
class InstantNoodles implements Noodles {
@Override
public void say() {
System.out.println("I am instant noodles");
}
}
// 面条工厂
class NoodlesFactory {
public static Noodles create(String type) {
// 创建逻辑
if (type.equalsIgnoreCase("HandPulled")) {
return new HandPulledNoodles();
} else if (type.equalsIgnoreCase("Instant")) {
return new InstantNoodles();
} else {
return null;
}
}
}
public class SimpleFactory {
public static void main(String[] args) {
Noodles n = NoodlesFactory.create(args[0]);
// 业务逻辑
if (n != null) {
n.say();
} else {
System.out.println("Parameter error");
}
}
}
可以看到,已经将创建逻辑转移到工厂类中。在main方法中,只是根据启动参数调用工厂类的静态方法创建面条实例。创建什么类型的面条由启动参数决定,main方法不需要知道具体的面条类型,这就实现了创建与业务的分离解耦,具有更好的扩展性。假如新增加一种意大利面,则只需要新定义一种面条,然后修改工厂类的实现,而main中的业务逻辑则不需要修改,代码如下:
// 面条接口
interface Noodles {
public void say();
}
// 拉面
class HandPulledNoodles implements Noodles {
@Override
public void say() {
System.out.println("I am hand-pulled noodles");
}
}
// 方便面
class InstantNoodles implements Noodles {
@Override
public void say() {
System.out.println("I am instant noodles");
}
}
// 意大利面
class PastaNoodles implements Noodles {
@Override
public void say() {
System.out.println("I am instant noodles");
}
}
// 面条工厂
class NoodlesFactory {
public static Noodles create(String type) {
// 创建逻辑
if (type.equalsIgnoreCase("HandPulled")) {
return new HandPulledNoodles();
} else if (type.equalsIgnoreCase("Instant")) {
return new InstantNoodles();
} else if (type.equalsIgnoreCase("Pasta")) {
return new PastaNoodles();
}
else {
return null;
}
}
}
public class SimpleFactory {
public static void main(String[] args) {
Noodles n = NoodlesFactory.create(args[0]);
// 业务逻辑
if (n != null) {
n.say();
} else {
System.out.println("Parameter error");
}
}
}
2、方法工厂模式
方法工厂模式与简单工厂模式实现方式基本一样,它只是对简单工厂模式的一种扩展。解决的问题是当产品的各类太多时,我们可以提供多种不同的工厂分别生产,不同的工厂类都实现同样的工厂接口。
首先对上例中面条的种类进行扩展,提供加牛肉的面条(修饰器模式),注意这不是水平扩展而是垂直扩展。修改后的代码:
// 面条接口
interface Noodles {
public void say();
}
// 加了牛肉的面条
class BeefNoodles implements Noodles {
private Noodles commonNoodles;
public BeefNoodles(Noodles noodles) {
commonNoodles = noodles;
}
@Override
public void say() {
commonNoodles.say();
System.out.println("Add beef");
}
}
// 拉面
class HandPulledNoodles implements Noodles {
@Override
public void say() {
System.out.println("I am hand-pulled noodles");
}
}
// 方便面
class InstantNoodles implements Noodles {
@Override
public void say() {
System.out.println("I am instant noodles");
}
}
// 意大利面
class PastaNoodles implements Noodles {
@Override
public void say() {
System.out.println("I am instant noodles");
}
}
// 面条工厂接口
interface NoodlesFactory {
public Noodles create(String type);
}
// 普通面条工厂
class ComNoodlesFactory implements NoodlesFactory {
public Noodles create(String type) {
// 创建逻辑
if (type.equalsIgnoreCase("HandPulled")) {
return new HandPulledNoodles();
} else if (type.equalsIgnoreCase("Instant")) {
return new InstantNoodles();
} else if (type.equalsIgnoreCase("Pasta")) {
return new PastaNoodles();
} else {
return null;
}
}
}
// 牛肉面条工厂
class BeefNoodlesFactory implements NoodlesFactory {
public Noodles create(String type) {
// 创建逻辑
if (type.equalsIgnoreCase("HandPulled")) {
return new BeefNoodles(new HandPulledNoodles());
} else if (type.equalsIgnoreCase("Instant")) {
return new BeefNoodles(new InstantNoodles());
} else if (type.equalsIgnoreCase("Pasta")) {
return new BeefNoodles(new PastaNoodles());
} else {
return null;
}
}
}
public class MethodFactory {
public static void main(String[] args) {
// 创建工厂
NoodlesFactory nFactory = null;
if (args[0].equalsIgnoreCase("y")) {
nFactory = new BeefNoodlesFactory();
} else {
nFactory = new ComNoodlesFactory();
}
// 生产面条
Noodles n = nFactory.create(args[1]);
// 业务逻辑
if (n != null) {
n.say();
} else {
System.out.println("Parameter error");
}
}
}
可以看到,通过修饰器模式,我们新增加了一大类面条,加牛肉的面条。相应的,也提交了两种类型的面条工厂,一种生产普通面条,一种生产加了牛肉的面条。
这种方法的缺点是当面条的种类很多时,如加辣椒的面条、加醋的面条时,需要对每种面条都提供相应的工厂类实现。另外在main方法中也就是业务逻辑中,与具体的工厂类产生了耦合,不利于代码的扩展。想当然的,我们可以把创建工厂的逻辑也转移出去,搞一个创建工厂的工厂,暂时把它理解成“抽象工厂”模式,我不知道这样理解是否正确。
3、抽象工厂模式
上述代码将创建工厂的逻辑与业务逻辑混合在一起了,继续分离,代码如下:
// 面条接口
interface Noodles {
public void say();
}
// 加了牛肉的面条
class BeefNoodles implements Noodles {
private Noodles commonNoodles;
public BeefNoodles(Noodles noodles) {
commonNoodles = noodles;
}
@Override
public void say() {
commonNoodles.say();
System.out.println("Add beef");
}
}
// 拉面
class HandPulledNoodles implements Noodles {
@Override
public void say() {
System.out.println("I am hand-pulled noodles");
}
}
// 方便面
class InstantNoodles implements Noodles {
@Override
public void say() {
System.out.println("I am instant noodles");
}
}
// 意大利面
class PastaNoodles implements Noodles {
@Override
public void say() {
System.out.println("I am instant noodles");
}
}
// 面条工厂接口
interface NoodlesFactoryInf {
public Noodles create(String type);
}
// 面条工厂实现
abstract class NoodlesFactory {
// 私有静态内部类:普通面条工厂
private static class ComNoodlesFactory implements NoodlesFactoryInf {
public Noodles create(String type) {
// 创建逻辑
if (type.equalsIgnoreCase("HandPulled")) {
return new HandPulledNoodles();
} else if (type.equalsIgnoreCase("Instant")) {
return new InstantNoodles();
} else if (type.equalsIgnoreCase("Pasta")) {
return new PastaNoodles();
} else {
return null;
}
}
}
// 私有静态内部类:牛肉面条工厂
private static class BeefNoodlesFactory implements NoodlesFactoryInf {
public Noodles create(String type) {
// 创建逻辑
if (type.equalsIgnoreCase("HandPulled")) {
return new BeefNoodles(new HandPulledNoodles());
} else if (type.equalsIgnoreCase("Instant")) {
return new BeefNoodles(new InstantNoodles());
} else if (type.equalsIgnoreCase("Pasta")) {
return new BeefNoodles(new PastaNoodles());
} else {
return null;
}
}
}
public static NoodlesFactoryInf createFactory(String kind) {
if (kind.equalsIgnoreCase("Beef")) {
return new BeefNoodlesFactory();
} else {
return new ComNoodlesFactory();
}
}
}
public class MethodFactory {
public static void main(String[] args) {
// 生产面条
Noodles n = NoodlesFactory.createFactory(args[0]).create(args[1]);
// 业务逻辑
if (n != null) {
n.say();
} else {
System.out.println("Parameter error");
}
}
}
上例中的工厂类实现是抽象类,用户不能也不需要实例化这个类。工厂类中包含私有内部静态类,负责生产具体种类的面条。main方法中不需要关心有多少种面条,有多少种面条工厂,只需要调用静态方法并传递参数就可以了。
另外如果新增加了一种面条,除了新的面条类本身,只需要修改工厂类实现中的普通面条的内部静态类。如果新增加了另外一大类面条,如加辣椒,则除了加辣椒这个类本身外,只需要在工厂类实现中新增加静态内部类并为createFactory新加一个分支就可以了。这是一种比较理解的工厂模式实现方式。