抽象工厂模式

什么是抽象工厂模式

提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类.

使用抽象工厂模式有什么好处,它和抽象工厂模式有什么区别?

1.所有的工厂都是用来封装对象的创建
2.简单工厂虽然不是真正的设计模式,但仍不失为一个简单的方法,可以将客户程序从具体类中解耦
3.工厂方法使用继承:把对象的创建委托给子类,子类实现工厂方法来创建对象
4.抽象工厂使用对象组合:对象的创建被实现在工厂接口所暴露出来的方法中
5.所有的工厂模式都通过减少应用程序和具体类之间的依赖促进松耦合
6.工厂方法允许类将实例化延迟到子类进行
7.抽象工厂创建相关的对象家族,而不需要依赖它们的具体类
8.依赖倒置原则指导我们避免依赖具体类型,而要尽量依赖抽象
9.工厂是很有威力的技巧,帮助我们针对抽象编程,而不需要针对具体类编程

举例说明

这次我们的抽象工厂模式来自于之前的工厂模式改装
我们先创建一个原料工厂,纽约有纽约的原料工厂,芝加哥有芝加哥的原料工厂,但是不管是哪个工厂都必须实现这个原料工厂

1
2
3
4
5
6
7
8
9
10
11
/**
* 原料工厂接口
*/
public interface PizzaIngredientFactory {
public Dough createDough();
public Sauce createSauce();
public Cheese createCheese();
public Veggies[] createVeggies();
public Pepperoni createPepperoni();
public Clams createClam();
}

接下来我们创建原料接口,所有的原料都必须实现这个接口

1
2
3
4
5
6
/**
* 奶酪接口
*/
public interface Cheese {
}

1
2
3
4
5
6
/**
* 蛤蚌接口
*/
public interface Clams {
}
1
2
3
4
5
6
/**
* 面团接口
*/
public interface Dough {
}
1
2
3
4
5
6
/**
* 意大利香肠
*/
public interface Pepperoni {
}
1
2
3
4
5
6
/**
* 调料
*/
public interface Sauce {
}
1
2
3
4
5
6
/**
* 蔬菜
*/
public interface Veggies {
}

好了,我们现在已经拥有了制作披萨的所有原料接口,接下来创建一组制作披萨的原料
先制作纽约披萨店制作披萨所需要的原料

1
2
3
4
5
6
7
8
/**
* 纽约人喜欢吃新鲜的蛤蚌
*/
public class FreshClams implements Clams {
public FreshClams(){
System.out.println("纽约风格的新鲜蛤蜊");
}
}

1
2
3
4
5
6
7
8
/**
* 纽约版本的调料
*/
public class MarinaraSauce implements Sauce {
public MarinaraSauce(){
System.out.println("纽约风格酱料");
}
}
1
2
3
4
5
6
7
8
/**
* 纽约风格的奶酪
*/
public class ReggianoCheese implements Cheese{
public ReggianoCheese(){
System.out.println("纽约风格奶酪");
}
}
1
2
3
4
5
6
7
8
/**
* 纽约风格的意大利肠
*/
public class SlicedPepperoni implements Pepperoni{
public SlicedPepperoni(){
System.out.println("纽约风格意大利肠");
}
}
1
2
3
4
5
6
7
8
/**
* 纽约版本的面团
*/
public class ThinCrustDough implements Dough {
public ThinCrustDough(){
System.out.println("勤劳的纽约人自己揉的面团");
}
}

再来创建芝加哥披萨店创建披萨所需要的原料

1
2
3
4
5
6
7
8
/**
* 芝加哥风格奶酪
*/
public class ChicagoCheese implements Cheese{
public ChicagoCheese(){
System.out.println("芝加哥风格奶酪");
}
}

1
2
3
4
5
6
7
8
/**
* 芝加哥人自己揉的面团
*/
public class ChicagoDough implements Dough {
public ChicagoDough(){
System.out.println("芝加哥人自己揉的面团");
}
}
1
2
3
4
5
6
7
8
/**
* 芝加哥风味意大利肠
*/
public class ChicagoPepperoni implements Pepperoni{
public ChicagoPepperoni(){
System.out.println("芝加哥风味意大利肠");
}
}
1
2
3
4
5
6
7
8
/**
* 芝加哥风格酱料
*/
public class ChicagoSauce implements Sauce {
public ChicagoSauce(){
System.out.println("芝加哥风格酱料");
}
}
1
2
3
4
5
6
7
8
/**
* 芝加哥人不喜欢新鲜的蛤蜊
*/
public class ChicagoClams implements Clams {
public ChicagoClams(){
System.out.println("芝加哥人不喜欢新鲜的蛤蜊");
}
}

再来一个通用的蔬菜

1
2
3
4
5
6
7
8
/**
* 大蒜
*/
public class Garlic implements Veggies{
public Garlic(){
System.out.println("添加一点大蒜");
}
}

1
2
3
4
5
6
7
8
/**
* 蘑菇
*/
public class Mushroom implements Veggies{
public Mushroom(){
System.out.println("蘑菇来一点");
}
}
1
2
3
4
5
6
7
8
/**
* 洋葱
*/
public class Onion implements Veggies{
public Onion(){
System.out.println("洋葱加一点");
}
}
1
2
3
4
5
6
7
8
/**
* 红辣椒
*/
public class Redpepper implements Veggies{
public Redpepper(){
System.out.println("红辣椒还是很不错的");
}
}

现在我们已经有了披萨的原料,现在我们创建一个披萨父类,所有披萨都要继承自该类,该类里有制作披萨的所有原料

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public abstract class Pizza {
String name;
Dough dough;//面团
Sauce sauce;//佐料 调味料
Veggies[] veggies;//蔬菜
Cheese cheese;//奶酪
Pepperoni pepperoni;//意大利切片肠
Clams clams;//蛤蚌
abstract void prepare();
void bake(){//烘烤
System.out.println("烘烤25分钟到30分钟...");
}
void cut(){//切片
System.out.println("把这个pizza按照对角线大卸八块...");
}
void box(){//打包
System.out.println("最后把pizza打包...");
}
void setName(String name){
this.name = name;
}
public String getName(){
return name;
}
}

现在我们要开始加工披萨了,先创建纽纽约和芝加哥的原料工厂

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/**
* 纽约原料工厂
*/
public class NYPizzaIngredientFactory implements PizzaIngredientFactory {
@Override
public Dough createDough() {
return new ThinCrustDough();
}
@Override
public Sauce createSauce() {
return new MarinaraSauce();
}
@Override
public Cheese createCheese() {
return new ReggianoCheese();
}
@Override
public Veggies[] createVeggies() {
Veggies[] veggies = {new Garlic(),new Onion(),new Mushroom(),new Redpepper()};
return veggies;
}
@Override
public Pepperoni createPepperoni() {
return new SlicedPepperoni();
}
@Override
public Clams createClam() {
return new FreshClams();
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/**
* 芝加哥原料工厂
*/
public class ChicagoPizzaIngredientFactory implements PizzaIngredientFactory {
@Override
public Dough createDough() {
return new ChicagoDough();
}
@Override
public Sauce createSauce() {
return new ChicagoSauce();
}
@Override
public Cheese createCheese() {
return new ChicagoCheese();
}
@Override
public Veggies[] createVeggies() {
Veggies[] veggies = {new Garlic(),new Onion(),new Mushroom(),new Redpepper()};
return veggies;
}
@Override
public Pepperoni createPepperoni() {
return new ChicagoPepperoni();
}
@Override
public Clams createClam() {
return new ChicagoClams();
}
}

好了我们现在和工厂已经谈妥了,他们会为我们持续供应原材料
现在我们要开两个店,首先我们创建一个总店,所有的店面都必须继承自该类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public abstract class PizzaStore {
public Pizza orderPizza(String type){
Pizza pizza;
pizza = createPizza(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
protected abstract Pizza createPizza(String type);
}

现在我们来开具体的店铺

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* 纽约披萨店
*/
public class NYCPizzaStore extends PizzaStore{
@Override
protected Pizza createPizza(String type) {
Pizza pizza = null;
PizzaIngredientFactory pizzaIngredientFactory = new NYPizzaIngredientFactory();
if("cheese".equals(type)){
pizza = new CheesePizza(pizzaIngredientFactory);
pizza.setName("NYC风格的奶酪披萨");
}else if("clam".equals(type)){
pizza = new ClamPizza(pizzaIngredientFactory);
pizza.setName("NYC风格的蛤蜊披萨");
}
return pizza;
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* 芝加哥披萨店
*/
public class ChicagoPizzaStore extends PizzaStore{
@Override
protected Pizza createPizza(String type) {
Pizza pizza = null;
PizzaIngredientFactory pizzaIngredientFactory = new ChicagoPizzaIngredientFactory();
if("cheese".equals(type)){
pizza = new CheesePizza(pizzaIngredientFactory);
pizza.setName("芝加哥风味的奶酪披萨");
}else if("clam".equals(type)){
pizza = new ClamPizza(pizzaIngredientFactory);
pizza.setName("芝加哥风味的蛤蜊披萨");
}
return pizza;
}
}

至此我们已经完成了所有的从原料到到工厂到店面,现在我们已经可以开张了
我们目前有两种口味的披萨

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* 奶酪披萨
*/
public class CheesePizza extends Pizza{
PizzaIngredientFactory pizzaIngredientFactory;
public CheesePizza(PizzaIngredientFactory pizzaIngredientFactory){
this.pizzaIngredientFactory = pizzaIngredientFactory;
}
@Override
void prepare() {
System.out.println("Preparing准备 "+name);
dough = pizzaIngredientFactory.createDough();
sauce = pizzaIngredientFactory.createSauce();
cheese = pizzaIngredientFactory.createCheese();
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* 蛤蜊披萨
*/
public class ClamPizza extends Pizza{
PizzaIngredientFactory pizzaIngredientFactory;
public ClamPizza(PizzaIngredientFactory pizzaIngredientFactory){
this.pizzaIngredientFactory = pizzaIngredientFactory;
}
@Override
void prepare() {
System.out.println("Preparing准备 "+name);
dough = pizzaIngredientFactory.createDough();
sauce = pizzaIngredientFactory.createSauce();
cheese = pizzaIngredientFactory.createCheese();
}
}

现在已经万事俱备只欠东风了(订单)
写个测试类测试一下

1
2
3
4
5
6
7
8
9
10
11
12
public class Test {
public static void main(String[] args){
System.out.println("Ethan喜欢吃纽约披萨");
PizzaStore nycPizzaStore = new NYCPizzaStore();
nycPizzaStore.orderPizza("cheese");
System.out.println();
System.out.println("Joel相对于纽约披萨更喜欢芝加哥披萨");
PizzaStore chicagoPizzaStore = new ChicagoPizzaStore();
chicagoPizzaStore.orderPizza("clam");
}
}

输出结果

Ethan喜欢吃纽约披萨
Preparing准备 NYC风格的奶酪披萨
勤劳的纽约人自己揉的面团
纽约风格酱料
纽约风格奶酪
烘烤25分钟到30分钟…
把这个pizza按照对角线大卸八块…
最后把pizza打包…

Joel相对于纽约披萨更喜欢芝加哥披萨
Preparing准备 芝加哥风味的蛤蜊披萨
芝加哥人自己揉的面团
芝加哥风格酱料
芝加哥风格奶酪
烘烤25分钟到30分钟…
把这个pizza按照对角线大卸八块…
最后把pizza打包…

总结

使用工厂模式和抽象工厂模式都可以将对象的创建封装起来,以便将代码从具体的实现类中解耦。
多用组合,例如工厂模式我们要创建纽约风格的奶酪味披萨,我们这里就直接直接是奶酪味的披萨再和纽约组合起来,这样就实现了解耦