一、概述
工厂模式,是我们日常开发中,最常用的设计模式之一,工厂模式在Java程序体系可以说随处可见。它提供了一种创建对象的最佳方式,在创建对象的时候,不会对客户端暴露创建逻辑,并且通过使用一个共同的接口来创建新的对象。
工厂模式有3种不同的实现方式:
- 简单工厂模式:又叫做静态工厂方法模式。该模式是通过传⼊相关的类型来返回相应的类,这种方式比较单一,可扩展性相对较差。简单工厂模式看为工厂方法模式的一种特例,两者归为一类。
- 工厂方法模式:一个抽象产品类,可以派生出多个具体产品类。 一个抽象工厂类,可以派生出多个具体工厂类。每个具体工厂类只能创建一个具体产品类的实例。
- 抽象工厂模式:多个抽象产品类,每个抽象产品类可以派生出多个具体产品类。一个抽象工厂类,可以派生出多个具体工厂类。 每个具体工厂类可以创建多个具体产品类的实例。
二、优缺点
简单工厂模式
- 优点
(1)实现简单,可扩展。
(2)实现了对象创建与业务逻辑的分离。
(3)客户端无需知道所创建的具体产品类和类名。
- 缺点
(1)实例化对象的逻辑全部封装在一个工厂类里,每次需求变化都要单独修改工厂类(违反了开闭原则),而且出了异常可能没法正常工作。
(2)不方便扩展子类。
工厂方法模式
- 优点
符合开放-关闭原则(简称开-闭原则)将创建对象的逻辑与任务交给了工厂类。
- 缺点
每次新增产品,产品类都需要创建对应工厂类,增加了系统的开销。
抽象工厂模式
- 优点
复杂的抽象关联关系使得在类的内部对一系列产品组的管理很方便。
- 缺点
增加新的产品等级结构麻烦,需要对原有系统进行较大的修改,甚至需要修改抽象层代码,这显然会带来较大的不便,违背了开闭原则。
三、实现方式
简单工厂模式
UML类图设计
产品手机抽象类
public interface Phone {
void produce();
}
小米手机类
public class XiaomiPhone implements Phone{
@Override
public void produce() {
System.out.println("生产->小米手机");
}
}
华为手机类
public class HuaweiPhone implements Phone{
@Override
public void produce() {
System.out.println("生产->华为手机");
}
}
简单工厂类
public class PhoneFactory {
public static Phone producePhone(String type){
switch (type){
case "xiaomi":
return new XiaomiPhone();
case "huawei":
return new HuaweiPhone();
default:
return null;
}
}
}
代码如上,违反了开闭原则,不太容易扩展新产品类,如果产品改变,需要改变工厂的具体方法。
工厂方法模式
工厂方法模式与简单工厂模式相比,是在业务类的基础上封装了一层工厂。
UML类图设计
手机工厂抽象类
public interface PhoneFactory {
void producePhone();
}
手机工厂类
//小米手机工厂
public class XiaomiFactory implements PhoneFactory{
@Override
public void producePhone() {
XiaomiPhone xiaomiPhone = new XiaomiPhone();
xiaomiPhone.produce();
}
}
//华为手机工厂
public class HuaweiFactory implements PhoneFactory{
@Override
public void producePhone() {
HuaweiPhone huaweiPhone = new HuaweiPhone();
huaweiPhone.produce();
}
}
代码如上,工厂方法模式有工厂名不易修改,稳定的优点,但是若要增加新产品(如:平板),对于产品簇问题,代码会出现成倍增产、类爆炸的现象。
抽象工厂模式
抽象工厂模式主要是来解决产品簇问题。
产品簇是啥呢?
通俗点讲,比如苹果厂只生产苹果产品,而苹果产品包括了电脑,手机,耳机等,这些一系列的产品就是产品簇。
在工厂方法模式下,小米、华为只能生产手机这个产品,现在需要扩展平板产品,按照工厂方法模式设计的话,还需要写一个平板抽象类,具体的再去实现,那么之后再去生产别的产品呢,抽象工厂类会越来越多,实现的类也会越来越多。
现在增加一个平板产品,相当于增加了6个类。
则使用抽象工厂后,只需要增加3个类,而且产品簇越多,效果越明显。
抽象工厂类
public interface AbstractFactory {
//生产手机
void producePhone();
//生产平板
void producePad();
}
小米工厂类
public class XiaomiFactory implements AbstractFactory{
@Override
public void producePhone() {
XiaomiPhone xiaomiPhone = new XiaomiPhone();
xiaomiPhone.produce();
}
@Override
public void producePad() {
XiaomiPad xiaomiPad = new XiaomiPad();
xiaomiPad.produce();
}
}
华为工厂类
public class HuaweiFactory implements AbstractFactory{
@Override
public void producePhone() {
HuaweiPhone huaweiPhone = new HuaweiPhone();
huaweiPhone.produce();
}
@Override
public void producePad() {
HuaweiPad huaweiPad = new HuaweiPad();
huaweiPad.produce();
}
}
代码如上,抽象工厂模式的优点是将工厂类的方法减少,适用于增加工厂的情况。缺点是当产品等级发生变化时(比如在增加一个手表),都需要修改以前工厂产品的代码(每个工厂都需要多加一个),违反开闭原则。
所以产品等级总是变化的时候,那么抽象工厂就不合适。
四、常见应用场景
- Spring中的BeanFactory是简单工厂模式。
- Spring中的FactoryBean是工厂方法模式。
- 日志记录器:记录可能记录到本地硬盘、系统事件、远程服务器等,用户可以选择记录日志到什么地方。
- 数据库访问,当用户不知道最后系统采用哪一类数据库,以及数据库可能有变化时。
- 设计一个连接服务器的框架,需要三个协议,"POP3"、"IMAP"、"HTTP",可以把这三个作为产品类,共同实现一个接口。