工厂模式(Factory Pattern)属于创建型设计模式。如其名它提供了一种像实际场景中像加工厂的形式来进行创建类对象,其过程不会对客户端暴露创建逻辑,并且是通过使用共同的接口来返回新创建的对象。一般工厂模式双可分为简单工厂模式(Simple Factory)、工厂方法模式(Factory Method)和 抽象工厂模式(Abstract Factory),其中严格来讲简单工厂不算是一个标准的的设计模式,但是工厂方法和抽象工厂都是通过简单工厂演变而来。
在介绍简单工厂模式前,我们先来构思一个现实生活中真实的场景。假设有一个手机厂商要生产智能手机和智能手表两款硬件产品,我们用代码来表达一般会这样写:
public class Phone {
public void showInfo() {
System.out.println("手机性能很强悍!");
}
}
public class Watch {
public void showInfo() {
System.out.println("手表时尚时尚最时尚!");
}
}
// 客户端调用
public class Main {
public static void main(String[] args){
Phone phone = new Phone();
phone.showInfo();
Watch watch = new Watch();
watch.showInfo();
}
}
代码就是对现实的映照,所以上述代码是没有错的,但是这样的思维却使程序只为满足当前的需求,程序不容易维护、扩展和复用。例如要生产多个产品就需要new出多次,这种暴露的创建对象是完全可以将其封装起来。又如手机厂商应该专心做好手机的设计和系统调优,生产这种事情就交给代工厂来完成就好了。
那么我们来看看使用简单工厂模式来表达是怎么样的。
手机和手表都属于硬件,将它们抽象出来:
public abstract class Hardware {
public abstract void showInfo();
}
public class Phone extends Hardware {
@Override
public void showInfo() {
System.out.println("手机性能很强悍!");
}
}
public class Watch extends Hardware {
@Override
public void showInfo() {
System.out.println("手表时尚时尚最时尚!");
}
}
硬件工厂类:
public class HardwareFactory {
public static Hardware createHardware(String hardwareName) {
Hardware hardware = null;
switch (hardwareName) {
case "phone":
hardware = new Phone();
break;
case "watch":
hardware = new Watch();
break;
default:
throw new UnsupportedOperationException("不支持该操作");
}
return hardware;
}
}
调用者:
public class Main {
public static void main(String[] args){
Hardware phone = HardwareFactory.createHardware("phone");
phone.showInfo();
Hardware watch = HardwareFactory.createHardware("watch");
watch.showInfo();
}
}
上述代码中,因为手机和手表都是属于硬件类产品,所以将它们继承于一个硬件类,客户端也就是手机厂商只需要给硬件工厂一个明确的命令,说我要生产一个手机或手表的硬件,调用硬件工厂中的createHardware方法传入要生成的硬件名,硬件工厂收到命令就会按要求生产出对应的硬件产品。
普通的简单工厂有一个明显的缺点,就是只有生产硬件的一个对外方法,需要接收一个约定好的命名来进行生产对应的产品,这样如果客户端传递命令名称错误,则不能正确地创建出产品对象,而这时可以将工厂类进行一个改进,明确出能生产什么样的产品。代码如:
public class HardwareFactory {
public static Hardware createPhone() {
return new Phone();
}
public static Hardware createWatch() {
return new Watch();
}
}
调用者:
public class Main {
public static void main(String[] args){
Hardware phone = HardwareFactory.createPhone();
phone.showInfo();
Hardware watch = HardwareFactory.createWatch();
watch.showInfo();
}
}
简单工厂其实就是将同类产品进行归类,将对象生产过程进行封装,这很符合现实中的情况。而且客户端仅负责消息产品,而免除了直接创建产品对象的责任,这样就明确了各自的职责和权利,在业务场景较为简单时,这也很好地体现出代码设计的优点。
如上所述,简单工厂模式适用于业务场景较为简单情况下或者具体产品很少有增加的情况。而对象复杂的业务具体产品在不断增加的情况下就显得不太合适。
为什么?想象一下上面实际场景,当手机厂商后面开始进军智能家居如智能灯泡、智能电视等进行生产时,那代码层面上对产品部分来说是很简单,只需要创建一个灯泡或电视的类,然后继承于硬件抽象类便可以了,但是对硬件工厂就不友好了,因为每增加一个硬件产品,硬件工厂就得进行一次修改,这样为了一个新的业务就很容易影响到原有稳定的业务。
由于硬件工厂类中集中了所有产品实例的创建,而我们在开发中并未能预先考虑到后面新的业务场景,工厂承受的责任太重而且经常的改动,很难避免模块功能的蔓延,对系统的维护和扩展非常不利,这显然不是一个很好的做法,也就是违背了开闭原则。
遇上如上情景时,就应该由工厂方法模式来解决了。工厂方式模式也叫 “多态工厂模式”。工厂的多态也就是把工厂改造成像产品类一样进行抽象,由每一个子工厂来负责对应产品的创建。
手机和手表继承于硬件抽象类,跟简单工厂一样不需要做改变:
public abstract class Hardware {
public abstract void showInfo();
}
public class Phone extends Hardware {
@Override
public void showInfo() {
System.out.println("手机性能很强悍!");
}
}
public class Watch extends Hardware {
@Override
public void showInfo() {
System.out.println("手表时尚时尚最时尚!");
}
}
将工厂抽象成接口(抽象类也行):
public interface IHardwareFactory {
Hardware createHardware();
}
// 手机子工厂
public class PhoneFactory implements IHardwareFactory {
@Override
public Hardware createHardware() {
return new Phone();
}
}
// 手表子工厂
public class WatchFactory implements IHardwareFactory {
@Override
public Hardware createHardware() {
return new Watch();
}
}
调用者:
public class Main {
public static void main(String[] args){
IHardwareFactory phoneFactory = new PhoneFactory();
Hardware phone = phoneFactory.createHardware();
phone.showInfo();
IHardwareFactory watchFactory = new WatchFactory();
Hardware watch = watchFactory.createHardware();
watch.showInfo();
}
}
工厂方法模式是简单工厂模式的进一步改进版,简单工厂模式将产品进行了抽象由单个工厂创建和输出对象,而工厂方法模式还将工厂进一步的抽象,由多个子工厂来创建和输出对应的产品对象。核心工厂类不再负责所有产品的创建细节,它仅负责给具体子工厂定义必须实现的接口。这使得工厂方法模式可以允许系统在不修改工厂的情况下新增新产品的扩展。工厂方法模式在设计上完全完全符合开闭原则。
当然,工厂方法模式也有其明显的缺点,就是每增加一个产品时,都需要增加一个具体对应的子工厂,这使得系统中代码量的增加,在一定程序上也增加了系统的复杂度,这也并不是好事。
介绍抽象工厂模式前,我们先来理解两个概念。
产品等级结构:等级结构又叫继承结构,所以产品等级结构就是产品的继承结构。正如上述手机示例中,手机是一个抽象类,而其子类有MZ手机、XM手机、HW手机等。抽象手机与具体品牌的手机之间构成了一个产品等级结构,抽象手机是父类,而具体品牌的手机是其子类。手表同理。
产品族:位于不同产品等级结构中,有相关联的产品组成的家族。又正如上述示例中, MZ厂商生产了手机和手表,还有其他厂商XM、HW等也生产了手机和手表。MZ手机位于手机产品等级结构中,MZ手表位于手表产品等级结构中。而MZ手机和MZ手表构成了MZ产品族,同理,XM手机和XM手表构成了XM产品族,HW手机和HW手表构成了HW产品族。
简单工厂模式引入了产品等级结构,其继承关系是硬件和手机、手表,而工厂方法模式在其基础上再引入了对应的工厂等级结构来解决了简单工厂模式中工厂类职责太重的问题,而当产品非常多时就会出现大量的与之对应的工厂类。一旦业务逻辑变得复杂出现一个或多个产品族时,若继续使用工厂方式将会出现不可想象多的工厂类,而抽象工厂模式恰好就是解决产品等级结构与产品族存在的工厂模式进化版本。
硬件类还是最顶层的抽象类:
public abstract class Hardware {
public abstract void showInfo();
}
// 将手机也抽象出来
public abstract class Phone extends Hardware {
public abstract void slogan();
}
// 将手表也抽象出来
public abstract class Watch extends Hardware {
public abstract void slogan();
}
产品族的实际产品:
// MZ产品族
public class MzPhone extends Phone {
@Override
public void showInfo() { System.out.println("Mz手机性能很强悍!"); }
@Override
public void slogan() { System.out.println("Mz手机如你才华横溢!"); }
}
public class MzWatch extends Watch {
@Override
public void showInfo() { System.out.println("Mz手表时尚时尚最时尚!"); }
@Override
public void slogan() { System.out.println("Mz手表如你才华横溢!"); }
}
// XM产品族
public class XmPhone extends Phone {
@Override
public void showInfo() { System.out.println("Xm手机性能很强悍!"); }
@Override
public void slogan() { System.out.println("Xm手机年轻人第一台手机!"); }
}
public class XmWatch extends Watch {
@Override
public void showInfo() { System.out.println("Xm手表时尚时尚最时尚!"); }
@Override
public void slogan() { System.out.println("Xm手机年轻人第一只手表!"); }
}
// HW产品族
public class HwPhone extends Phone {
@Override
public void showInfo() { System.out.println("Hw手机性能很强悍!"); }
@Override
public void slogan() { System.out.println("Hw手机自主芯片就是牛!"); }
}
public class HwWatch extends Watch {
@Override
public void showInfo() { System.out.println("Hw手表时尚时尚最时尚!"); }
@Override
public void slogan() { System.out.println("Hw手表自主芯片就是牛!"); }
}
工厂:
// 类似多方法简单工厂模式,但将其抽象
public interface IHardwareFactory {
Hardware createPhone();
Hardware createWatch();
}
// MZ产品族工厂,就是一个多方法简单工厂
public class MzHardwareFactory implements IHardwareFactory {
@Override
public Phone createPhone() {
return new MzPhone();
}
@Override
public Watch createWatch() {
return new MzWatch();
}
}
// XM产品族工厂,就是一个多方法简单工厂
public class XmHardwareFactory implements IHardwareFactory {
@Override
public Phone createPhone() {
return new XmPhone();
}
@Override
public Watch createWatch() {
return new XmWatch();
}
}
// HW产品族工厂,就是一个多方法简单工厂
public class HwHardwareFactory implements IHardwareFactory {
@Override
public Phone createPhone() {
return new HwPhone();
}
@Override
public Watch createWatch() {
return new HwWatch();
}
}
调用者:
public class Main {
public static void main(String[] args){
MzHardwareFactory mzHardwareFactory = new MzHardwareFactory();
Phone mzPhone = mzHardwareFactory.createPhone();
mzPhone.showInfo();
mzPhone.slogan();
Watch mzWatch = mzHardwareFactory.createWatch();
mzWatch.showInfo();
mzWatch.slogan();
XmHardwareFactory xmHardwareFactory = new XmHardwareFactory();
Phone xmPhone = xmHardwareFactory.createPhone();
xmPhone.showInfo();
xmPhone.slogan();
Watch xmWatch = xmHardwareFactory.createWatch();
xmWatch.showInfo();
xmWatch.slogan();
HwHardwareFactory hwHardwareFactory = new HwHardwareFactory();
Phone hwPhone = hwHardwareFactory.createPhone();
hwPhone.showInfo();
hwPhone.slogan();
Watch hwWatch = hwHardwareFactory.createWatch();
hwWatch.showInfo();
hwWatch.slogan();
}
}
输出结果:
Mz手机性能很强悍!
Mz手机如你才华横溢!
Mz手表时尚时尚最时尚!
Mz手表如你才华横溢!
Xm手机性能很强悍!
Xm手机年轻人第一台手机!
Xm手表时尚时尚最时尚!
Xm手机年轻人第一只手表!
Hw手机性能很强悍!
Hw手机自主芯片就是牛!
Hw手表时尚时尚最时尚!
Hw手表自主芯片就是牛!
抽象工厂模式中,由每个工厂来统一管理一个产品族,单个工厂内生产不同的产品等级结构的产品。其实更直白地说,抽象工厂就是当存在产品族关系时,将简单工厂模式和工厂方法模式相结合,形成以产品族作为区分的多套简单工厂模式。抽象工厂模式在新增产品族时是符合开闭原则,工厂方法模式是在新增具体产品时增加对应产品的工厂,而抽象工厂模式是在新增一个产品族时才需要新增工厂。
但是抽象工厂模式在新增产品等级结构时就显然需要修改所有的产品族工厂,例如示例中要新增一个智能电视产品时,就要对三个产品族工厂进行修改,从而显示很糟糕。所以我们作为程序的开发者应该尽可能地在设计之初就要多考虑未来场景,否则将会导致系统出现较多的修改从而增加维护的成本。