抽象工厂模式算是工厂相关模式的终极形态,如果完全理解了上一章的工厂方法模式,那么抽象工厂模式就很好理解了。它与工厂方法唯一的区别就是工厂的接口里是一系列创造抽象产品的方法,而不再是一个,而相应的,抽象产品也不再是一个了,而是一系列相关的产品。这其实是工厂方法模式的一种扩展。
通常用继承和组合两种方式扩展一个接口或者类,一般我们推荐使用组合扩展一个现有的类或接口,但这并非绝对,如果你扩展的子类或子接口与现有的类或接口明显是“是一个(is a)”的关系,也就是继承的关系,那么使用继承可以获得更多的好处。
定义:为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类。
抽象工厂模式的类图:
首先要创建一个接口,这个接口就是指的Creator,而一组相关或者相互依赖的对象,就是指的ProductA和ProductB以及它们具体的实现类,我们返回的接口或者抽象类则是指的ProductA和ProductB接口。
java代码结构:
工厂类:
package net;
public interface Creator {
ProductA createProductA();
ProductB createProductB();
}
两个具体的工厂实现类:
package net;
public class ConcreteCreator1 implements Creator{
public ProductA createProductA() {
return new ProductA1();
}
public ProductB createProductB() {
return new ProductB1();
}
}
package net;
public class ConcreteCreator2 implements Creator{
public ProductA createProductA() {
return new ProductA2();
}
public ProductB createProductB() {
return new ProductB2();
}
}
然后由下向上是产品类和具体的产品实现类:
package net;
interface ProductA {
void methodA();
}
interface ProductB {
void methodB();
}
class ProductA1 implements ProductA{
public void methodA() {
System.out.println("产品A系列中1型号产品的方法");
}
}
class ProductA2 implements ProductA{
public void methodA() {
System.out.println("产品A系列中2型号产品的方法");
}
}
class ProductB1 implements ProductB{
public void methodB() {
System.out.println("产品B系列中1型号产品的方法");
}
}
class ProductB2 implements ProductB{
public void methodB() {
System.out.println("产品B系列中2型号产品的方法");
}
}
下面是测试类:
package net;
public class Client {
public static void main(String[] args) throws Exception {
Creator creator = new ConcreteCreator1();
ProductA productA = creator.createProductA();
ProductB productB = creator.createProductB();
productA.methodA();
productB.methodB();
//切换具体的工厂实现类
creator = new ConcreteCreator2();
productA = creator.createProductA();
productB = creator.createProductB();
productA.methodA();
productB.methodB();
}
}
测试类中我们切换了一次工厂实现类,而实际中生产的产品就有了差别。
简单的说:不管是简单工厂,还是工厂方法,都有一个缺陷,那就是整个模式当中只能有一个抽象产品,所以直观的,在工厂方法模式中再添加一个创造抽象产品的方法就是抽象工厂模式了,相应的当然还有添加一个抽象产品,还有一系列具体的该抽象产品的实现。
简单工厂模式,工厂方法模式一直到抽象工厂模式的演变过程,三者是由简到繁的关系。他们的代码结构如下:
简单工厂:
//抽象产品
interface Product{}
//具体产品
class ProductA implements Product{}
class ProductB implements Product{}
//产品工厂(下一步就是它的进化,就变成了工厂方法模式)
public class ProductFactory {
private ProductFactory(){}
public static Product getProduct(String productName){
if (productName.equals("A")) {
return new ProductA();
}else if (productName.equals("B")) {
return new ProductB();
}else {
return null;
}
}
}
工厂模式(简单工厂有关产品的类和接口是不变的):
//抽象产品
interface Product{}
//具体产品
class ProductA implements Product{}
class ProductB implements Product{}
//将简单工厂中的工厂给抽象成接口
interface Factory{
Product getProduct();
}
//具体的工厂A,创造产品A
class FactoryA implements Factory{
public Product getProduct() {
return new ProductA();
}
}
//具体的工厂B,创造产品B
class FactoryB implements Factory{
public Product getProduct() {
return new ProductB();
}
}
产品部分并没有变化,只是将简单工厂中的工厂类抽象成接口,并给相应产品添加相应的工厂类,就进化成了工厂方法模式。
抽象工厂模式:
//抽象产品
interface Product{}
//具体产品
class ProductA implements Product{}
class ProductB implements Product{}
//多了一个抽象产品1
interface Product1{}
//具体产品1
class Product1A implements Product1{}
class Product1B implements Product1{}
//原有的工厂方法模式的工厂里添加一个方法
interface Factory{
Product getProduct();
//添加另外一个产品族的创造方法
Product1 getProduct1();
}
//具体的工厂A,创造产品A
class FactoryA implements Factory{
public Product getProduct() {
return new ProductA();
}
//添加相应的实现
public Product1 getProduct1() {
return new Product1A();
}
}
//具体的工厂B,创造产品B
class FactoryB implements Factory{
public Product getProduct() {
return new ProductB();
}
//添加相应的实现
public Product1 getProduct1() {
return new Product1B();
}
}
与工厂方法对比下就发现,多了一个产品系列叫Product1,工厂接口里多了一个方法,叫getProduct1,所以抽象工厂模式就是工厂方法模式添加了抽象产品所演变而来的。
三者有着很大的关联和明显的关系,下面罗列下这三种设计模式依次进化的原因。
1,首先从简单工厂进化到工厂方法,是因为工厂方法弥补了简单工厂对修改开放的弊端,即简单工厂违背了开闭原则。
2,从工厂方法进化到抽象工厂,是因为抽象工厂弥补了工厂方法只能创造一个系列的产品的弊端。
如果使用工厂模式去解决抽象工厂的场景,我们需要建立做个工厂模式对对应每一个产品系列。
不过,如果是引用第三方的jar中的工厂模式,原有的Product和Factory接口包括它们的一套实现是不可更改的,我们可以将jar包中的工厂方法模式扩展成抽象工厂模式来达到我们的目的:
//抽象产品
interface Product{}
//具体产品
class ProductA implements Product{}
class ProductB implements Product{}
//工厂接口
interface Factory{
Product getProduct();
}
//具体的工厂A,创造产品A
class FactoryA implements Factory{
public Product getProduct() {
return new ProductA();
}
}
//具体的工厂B,创造产品B
class FactoryB implements Factory{
public Product getProduct() {
return new ProductB();
}
}
/* 假设以上是一个第三方jar包中的工厂方法模式,我们无法改动源码 */
//我们自己特有的产品
interface MyProduct{}
//我们自己特有的产品实现
class MyProductA implements MyProduct{}
class MyProductB implements MyProduct{}
//扩展原有的工厂接口
interface MyFactory extends Factory{
MyProduct getMyProduct();
}
//我们自己特有的工厂A,扩展自原有的工厂A,并且实现获得我们自己特有产品的接口方法
class MyFactoryA extends FactoryA implements MyFactory{
public MyProduct getMyProduct() {
return new MyProductA();
}
}
//同A
class MyFactoryB extends FactoryB implements MyFactory{
public MyProduct getMyProduct() {
return new MyProductB();
}
}
这样我们就可以得到我们自己特有的抽象工厂和使用我们自己特有的产品了,并且我们自己的抽象工厂还兼并了第三方jar包中的产品,例如,我们可以使用MyFactoryA获得jar包中的ProductA产品等。
这种方式的好处是我们可以完整的复用jar包中的各个类功能,缺点是继承会导致系统的复杂性增加,耦合度相对较高。
所以我们还可以有另外一种做法,就是创造我们自己的一套独有的工厂方法模式,这套体系与jar包中的类和接口毫无关系,我们再使用一个组合工厂将二者结合起来:
//抽象产品
interface Product{}
//具体产品
class ProductA implements Product{}
class ProductB implements Product{}
//工厂接口
interface Factory{
Product getProduct();
}
//具体的工厂A,创造产品A
class FactoryA implements Factory{
public Product getProduct() {
return new ProductA();
}
}
//具体的工厂B,创造产品B
class FactoryB implements Factory{
public Product getProduct() {
return new ProductB();
}
}
/* 假设以上是一个第三方jar包中的工厂方法模式,我们无法改动源码 */
//我们自己特有的产品
interface MyProduct{}
//我们自己特有的产品实现
class MyProductA implements MyProduct{}
class MyProductB implements MyProduct{}
//我们自己的工厂接口
interface MyFactory{
MyProduct getMyProduct();
}
//我们自己特有的工厂A,产生产品A
class MyFactoryA implements MyFactory{
public MyProduct getMyProduct() {
return new MyProductA();
}
}
//我们自己特有的工厂B,产生产品B
class MyFactoryB implements MyFactory{
public MyProduct getMyProduct() {
return new MyProductB();
}
}
/* 到这里是我们自己的一套工厂方法模式,去创造我们自己的产品,以下我们将以上二者组合 */
//我们使用组合的方式将我们的产品系列和jar包中的产品组合起来
class AssortedFactory implements MyFactory,Factory{
MyFactory myFactory;
Factory factory;
public AssortedFactory(MyFactory myFactory, Factory factory) {
super();
this.myFactory = myFactory;
this.factory = factory;
}
public Product getProduct() {
return factory.getProduct();
}
public MyProduct getMyProduct() {
return myFactory.getMyProduct();
}
}
组合的工厂AssortedFactory集成了我们自己的工厂和jar包中的工厂两者的功能。这样做则会非常灵活,因为我们的一套体系不再依赖于jar包中的类或接口而存在,哪怕是jar包中的类改变或者不在了,我们自己的这一套依旧可以独立存在。
很难说那种方式更好,具体还是要根据实际的情况去掂量各个方式的利弊,从而选择出一种更适合当前情况的处理方式。