Abstract Factory(抽象工厂)
在此之前,已经学习过了Factory Method(工厂方法),抽象工厂和工厂方法这两个模式都属于创建型设计模式,那么根据[工厂]这个词,大概也能猜出这两个模式都是用来“生产”的
那么这两种用来“生产”的模式 ——— 抽象工厂和工厂方法,这两个设计模式有什么区别呢?或者说也两个模式“生产”的东西有什么不同的吗?
在之前工厂方法的简单实现中,举了个工厂制作蛋糕的例子,那么现在我们的蛋糕店需要生产两种蛋糕,分别为草莓口味的红色的爱心型蛋糕和芒果口味的黄色的方形蛋糕,这两个都是具体的产品,换句话说,对于草莓味心型蛋糕,心型模具和草莓味奶油都是只用来生产这类蛋糕的,那如果我们想做一个爱心型的芒果蛋糕呢?难道还要做一个只属于芒果蛋糕的模具吗?
不,当然不是,在日常生活中,对于这种情况,应该是拿一个爱心模具来做一类爱心型蛋糕,而不会说一种蛋糕做一个模具
到这里,或许对于抽象工厂和工厂方法的区别还是有点模糊
那么,现在来总结一下,
- 如果是用来生成一个复杂的对象,他的内部元素无法抽象出来时,选择工厂方法模式
- 如果是用来生产具体细节抽象的产品,产品的内部元素可变,选择抽象工厂
说了这么多,但是还没有见到抽象模式的真身,下面先介绍一下抽象工厂模式,然后,再重新打造我们的工厂,让其能够生产更多类型的蛋糕
Abstract Factory(抽象工厂)的UML类图
- AbstractProductA:抽象产品A
- ConcreteProductA1:具体产品A1
- ConcreteProductA2:具体产品A2
- AbstractProductB:抽象产品B
- ConcreteProductB1:具体产品B1
- ConcreteProductB2:具体产品B2
- AbstractFactory:抽象工厂,内部有两个方法,分别用来生产不同的产品,最后成一个整体
- ConcreteFactory1:具体工厂1
- ConcreteFactory2:具体工厂2
先创建产品的抽象类 AbstractProductA
public abstract class AbstractProductA {
public abstract void doA();
}
AbstractProductB
public abstract class AbstractProductB {
public abstract void doB();
}
然后再来打造具体的产品细节 ConcreteProductA1
public class ConcreteProductA1 extends AbstractProductA {
@Override
public void doA() {
System.out.println("Concrete Product A 1");
}
}
ConcreteProductA2
public class ConcreteProductA2 extends AbstractProductA {
@Override
public void doA() {
System.out.println("Concrete Product A 2");
}
}
ConcreteProductB1
public class ConcreteProductB1 extends AbstractProductB {
@Override
public void doB() {
System.out.println("Concrete Product B 1");
}
}
ConcreteProductB2
public class ConcreteProductB2 extends AbstractProductB {
@Override
public void doB() {
System.out.println("Concrete Product B 2");
}
}
OK,关于具体的产品细节已经做好了,现在最关键的就是通过工厂,来将这些细节组装成一个具体的产品
首先,在打造一个抽象工厂
AbstractFactory
public abstract class AbstractFactory {
// 生产产品细节A
public abstract AbstractProductA createProductA();
// 生产产品细节B
public abstract AbstractProductB createProductB();
}
好了,接下来就是根据需要打造具体的工厂了 ConcreteFactory1:生产产品细节A1和产品细节B2
public class ConcreteFactory1 extends AbstractFactory {
@Override
public AbstractProductA createProductA() {
return new ConcreteProductA1();
}
@Override
public AbstractProductB createProductB() {
return new ConcreteProductB2();
}
}
ConcreteFactory2:生产产品细节A2和产品细节B1
public class ConcreteFactory2 extends AbstractFactory {
@Override
public AbstractProductA createProductA() {
return new ConcreteProductA2();
}
@Override
public AbstractProductB createProductB() {
return new ConcreteProductB1();
}
}
好了,现在我们只需要通过这两个工厂,就能得到一个具有A和B两种不同细节的产品
抽象工厂模式的简单实现
还是挺简单的,那么,接下来,借助上面的经验,是时候将蛋糕店好好装修一番了,让蛋糕店可以生产各种各样的产品
首先,分析一下,对于蛋糕
- 按照造型分,我们有爱心型的和方形的,
- 按照奶油分,我们有红色的草莓味和黄色的芒果味
那么根据调查发现(是我瞎说的~),现在爱心型的草莓味蛋糕和芒果味的方形蛋糕是卖的最火的,所以,蛋糕店也需要与时俱进,将要生产这种两种蛋糕
好了,分析完了,我们先根据造型,打造一个抽象造型产品(或者说是蛋糕模板也可以啦~)
抽象造型产品
public abstract class CakeStyle {
public abstract void style();
}
再根据奶油,打造一个抽象奶油产品
抽象奶油产品
public abstract class CakeCream {
public abstract void cream();
}
OK,下面分别开始制作爱心型模板,方形模板,草莓味奶油,芒果味奶油
爱心型模板
public class HeartStyle extends CakeStyle {
@Override
public void style() {
System.out.println("Heart Style");
}
}
方形模板
public class SquareStyle extends CakeStyle {
@Override
public void style() {
System.out.println("Square Style");
}
}
草莓味奶油
public class StrawberryCream extends CakeCream {
@Override
public void cream() {
System.out.println("Strawberry Cream");
}
}
芒果味奶油
public class MangoCream extends CakeCream {
@Override
public void cream() {
System.out.println("Mango Cream");
}
}
现在,无论是材料还是工具都做好了,只要根据需要,通过具体的工厂生产就行了
首先,还是来一个抽象工厂
public abstract class CakeFactory {
public abstract CakeCream cream();
public abstract CakeStyle style();
}
然后,就分别是爱心型草莓味蛋糕工厂和方形芒果味蛋糕工厂
爱心型草莓味蛋糕工厂
public class StrawberryHeartCake extends CakeFactory{
@Override
public CakeCream cream() {
return new StrawberryCream();
}
@Override
public CakeStyle style() {
return new HeartStyle();
}
}
方形芒果味蛋糕工厂
public class MangoSquareCake extends CakeFactory {
@Override
public CakeCream cream() {
return new MangoCream();
}
@Override
public CakeStyle style() {
return new SquareStyle();
}
}
大功告成,让我们来看看蛋糕做得怎么样
public static void main(String[] args) {
CakeFactory strawberryHeartCake = new StrawberryHeartCake();
strawberryHeartCake.cream().cream();
strawberryHeartCake.style().style();
System.out.println();
CakeFactory mangoSquareCake = new MangoSquareCake();
mangoSquareCake.cream().cream();
mangoSquareCake.style().style();
}
result:
Strawberry Cream
Heart Style
Mango Cream
Square Style
还不赖嘛~
如果,这时需求变更了,比如,现在更流行吃爱心型芒果味蛋糕
那么我们只需要一个工厂就可以做 到了,而不需要再去重头开始制作奶油和模板
爱心型芒果味蛋糕
public class MangoHeartCake extends CakeFactory {
@Override
public CakeCream cream() {
return new MangoCream();
}
@Override
public CakeStyle style() {
return new HeartStyle();
}
}
还是挺简单的嘛~
好了,来总结一下抽象工厂的优缺点吧
- 优点:最明显的分离了抽象和实现,基于产品的抽象和实现的分离,是抽象工厂在切换产品类时更加灵活和容易
- 缺点:就像我们上面看到的,一个产品就需要一个工厂,那么根据产品的越来越多,具体工厂类就越来越多;另一个就是不容易扩展,比如现在有了新的需求,比如蛋糕现在生产时有了磅数(重量)的要求,那么我们就必须去修改抽象工厂类,从而导致所有的具体工厂类都必须修改