一、抽象工厂模式的本质
抽象工厂模式封装同一产品族(产品族可以认为是相关的产品,如电脑和鼠标键盘可称为一个产品族)的创建细节,工厂方法抽象了一个产品等级的创建细节(产品等级可以认为是同类产品按照不同的指标分成了不同的等级,如电脑的低配版、高配版、旗舰版等),一个产品族里面有不同类的产品(如电子产品族里面有手机、电脑、平板等,其中电子产品可认为是一个抽象的产品族,而手机、电脑、平板可认为是不同的产品等级或者类,手机产品类中又有苹果、华为、小米等),抽象工厂模式对产品族进行了抽象,抽象工厂就是在产品族这一层进行了抽象,也就是说她能够创建的产品种类更多。
抽象工厂模式的本质是通过提供统一的接口,保证在同一工厂中创建产品族中的不同产品(产品类/产品等级)。
二、抽象工厂模式目的
抽象工厂模式的目的是通过抽象工厂创建一系列相关的产品类对象,而无需指定其具体产品类。如上图所示,抽象工厂能够创建小米手机类对象或者其它产品类对象,而不需要客户端显示的使用new关键字来创建相关产品类的对象。同时,抽象工厂统一负责一个产品族中的不同产品等级的产品,这样就实现了对创建产品类对象的统一封装,也就是说,通过具体的抽象工厂类可以创建同一产品族中不同的产品等级的产品类对象。
三、示例场景
某个电脑公司的在线购物网站可售卖不同厂家(如小米、华为、苹果)的电脑、手机、平板等电子产品,网站需要为客户提供各种电子的配置信息查看功能,每当用户想查看某个电子产品配置时,需要给出该电子产品生产日期以及价格等信息。
注意事项:每个厂家都有可能随时新增新的产品。
四、代码实现及对比
从上述示例场景中可以看出,每个厂家都会出售手机、电脑、平板,根据抽象工厂模式的设计思想,我们可以分别将手机、电脑和平板设置为产品等级,将每个厂家的所有手机、电脑、平板设置为产品族,然后,通过抽象工厂统一提供统一产品族(厂家)中产品等级中的某个产品(如手机)。
IPad类定义(平板的抽象定义,此处用接口实现)
public interface IPad {
void Drawing(String picName);
void PlayingFilm(String filmName);
}
XiaomiPad类定义(具体平板产品类)
public class XiaomiPad implements IPad{
@Override
public void Drawing(String picName) {
System.out.println("Drawing a picture with 小米 Pad: " + picName);
}
@Override
public void PlayingFilm(String filmName) {
System.out.println("Watching a file with 小米 Pad: " + filmName);
}
}
HuaweiPad类定义(具体平板产品类)
public class HuaweiPad implements IPad{
@Override
public void Drawing(String picName) {
System.out.println("Drawing a picture with 华为 Pad: " + picName);
}
@Override
public void PlayingFilm(String filmName) {
System.out.println("Watching a file with 华为 Pad: " + filmName);
}
}
IPhone类定义(手机的抽象定义,此处用接口实现)
public interface IPhone {
void calling(String number);
void sendMessage(String msg);
}
XiaomiPhone类定义(具体手机产品类)
public class XiaomiPhone implements IPhone{
@Override
public void calling(String num) {
System.out.println("Make calls using your 小米 phone: "+num);
}
@Override
public void sendMessage(String msg) {
System.out.println("Send messages using your 小米 phone: "+msg);
}
}
HuaweiPhone类定义(具体手机产品类)
public class HuaweiPhone implements IPhone{
@Override
public void calling(String num) {
System.out.println("Make calls using your 华为 phone: "+ num);
}
@Override
public void sendMessage(String msg) {
System.out.println("Send messages using your 华为 phone: "+msg);
}
}
抽象工厂的抽象类定义(此处用接口实现)
public interface IAbstractFactory {
IPad createPad();
IPhone createPhone();
}
xiaomi工厂的定义(实现抽象工厂,提供产品族中各种产品的具体创建)
public class XiaomiFactory implements IAbstractFactory{
@Override
public IPad createPad() {
return new XiaomiPad();
}
@Override
public IPhone createPhone() {
return new XiaomiPhone();
}
}
Huawei工厂的定义(实现抽象工厂,提供产品族中各种产品的具体创建)
public class HuaweiFactory implements IAbstractFactory{
@Override
public IPad createPad() {
return new HuaweiPad();
}
@Override
public IPhone createPhone() {
return new HuaweiPhone();
}
}
客户端类定义
public class main {
public static void main(String[] args) {
System.out.println("Abstract Factory Pattern: client.");
/*使用抽象工厂模式来创建产品等级中的某类产品类对象*/
IAbstractFactory xiaomiFactory = new XiaomiFactory();
IPhone xiaomiPhone = xiaomiFactory.createIphone();
xiaomiPhone.calling("1111111111111");
xiaomiPhone.sendMessage("How are you?");
IPad xiaomiPad = xiaomiFactory.createPad();
xiaomiPad.PlayingFilm("Fast & Furious 9");
xiaomiPad.Drawing("Mona Lisa");
System.out.println("-----------------------------------------------------");
IAbstractFactory huaweiFactory = new HuaweiFactory();
IPhone huaweiPhone = huaweiFactory.createIphone();
huaweiPhone.calling("222222222");
huaweiPhone.sendMessage("Do you have a nice day?");
IPad huaweiPad = huaweiFactory.createPad();
huaweiPad.Drawing("The Last Supper");
huaweiPad.PlayingFilm("流浪地球");
}
}
注意:这里的具体的产品类的创建还可以配合工厂方法/简单工厂模式来实现,此处为了避免与工厂方法/简单工厂模式产生混淆,在具体产品工厂定义中就直接使用new关键字来创建具体的产品类了。
五、抽象工厂模式的UML类图
抽象工厂模式的关键类与相互的关系如上图所示。
IPad和IPhone为抽象类,定义了具体产品类的属性和方法;
HuaweiPad、XiaomiPad、HuaweiPhone、XiaomiPhone这四个类分别是上述两个抽象类的具体实现类,实现抽象类中定义的方法,如手机的打电话方法、平板的看电影方法;
IAbstractFactory类为抽象工厂类,定义了具体产品工厂需要提供的产品类创建的方法,需要包含整个产品族中所有产品类的创建方法;
XiaomiFactory和HuaweiFactory这两个类就是IAbstractFactory抽象类的具体实现类,分别实现了各自产品族中不同产品类的创建方法;
然后,客户端类通过创建具体工厂类开启具体产品类实例的创建,具体产品类实例对象的创建过程如下:
第一步:创建抽象工厂的具体实现类实例,如 IAbstractFactory xiaomiFactory = new XiaomiFactory();,这时候,小米工厂就可以创建小米这个产品族中不同的产品了;
第二步:利用具体工厂创建具体产品类实例对象,如IPhone xiaomiPhone = xiaomiFactory.createIphone();具体产品创建完成。
六、抽象工厂模式的优缺点
(1)优点
抽象工厂模式隔离了具体类的生产,使得客户并不需要了解具体产品如何被创建的。
当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。
-
增加新的具体工厂和产品族很方便,无须修改已有系统,符合“开闭原则”。
如上图所示,当需要新增产品族的时候,直接添加相关的具体产品类和工厂类即可。
(2)缺点
- 增加新的产品等级结构很复杂,需要修改抽象工厂和所有的具体工厂类,对“开闭原则”的支持呈现倾斜性。
如上图所示,当需要新增产品时,需要修改响应的工厂类(抽象和具体工厂类都需要修改),违反“开闭原则”。