# 前言
本程序改编自《Head First Design Patterns》(简称*HF* )中的关于Pizza的例子(可以在GitHub下载)。
![HF抽象工厂](https://box.kancloud.cn/2016-02-22_56cab10c88a10.jpg "")
图:*HF* 上的抽象工厂类图。Client位于图右上角。AbstractProductA的一个子类和AbstractProductB的一个子类,两个子类合在一起构成一个**产品族,即 a family of products**
*HF* 上面的例子的Client是一个抽象类,及其子类;然后又用了一个工厂方法模式,封装了new Client( )的过程。我觉得这样子没有必要,于是把书上的例子做了简化:把Client改成普通类;然后再用一个简单工厂封装new Client( )的过程。这样子丝毫不影响抽象工厂的精髓,反而还可以简化代码,突出重点。
PS. 实验楼网站里面的例子中,Client是一个普通类,没有用简单工厂或者工厂方法模式封装Client。我觉得这样子不好,因为这样直接把”Client的new的过程“暴露在Main里面了。
抽象工厂模式,可以和简单工厂或者工厂方法模式“组合在一起”,让后两者进一步封装抽象工厂中的Client。
# 严格的类图
总共14个java文件
- 两个抽象产品接口
- 四个具体产品类
- 一个抽象工厂接口
- 四个具体工厂类
- 一个Client类
- 一个封装Client类的简单工厂
- 一个Main类
![抽象工厂类图](https://box.kancloud.cn/2016-02-22_56cab10cc98f3.jpg "")
图:我绘制的类图,严格的抽象工厂模式类图(一些资料不区分聚合、关联、依赖,把这三种关系统统当作依赖关系)。我使用了一个叫做AmaterasUML 的插件。
# Talk is cheap, show me the code
### 两个抽象产品接口
~~~
package abstractFactory;
// 抽象产品A——蔬菜
public interface Veggies {
public String toString();
}
~~~
~~~
package abstractFactory;
// 抽象产品B——肉馅
public interface Meat {
public String toString();
}
~~~
### 四个具体产品类
~~~
package abstractFactory;
// 具体产品A1——白菜
public class Cabbage implements Veggies
{
public String toString()
{
return "白菜";
}
}
~~~
~~~
package abstractFactory;
// 具体产品A2——青椒
public class GreenPepper implements Veggies
{
public String toString()
{
return "青椒";
}
}
~~~
~~~
package abstractFactory;
// 具体产品B1——猪肉馅
public class Pork implements Meat {
public String toString()
{
return "猪肉";
}
}
~~~
~~~
package abstractFactory;
// 具体产品B2——牛肉馅
public class Beaf implements Meat
{
public String toString()
{
return "牛肉";
}
}
~~~
### 一个抽象工厂接口
~~~
package abstractFactory;
// 工厂接口
public interface BaoZiIngredientFactory
{
public abstract Veggies createVeggies(); // 蔬菜类产品
public abstract Meat createMeat(); // 肉类产品
}
~~~
### 四个具体工厂类
~~~
package abstractFactory;
// 具体工厂1生产的白菜猪肉包子
public class BaoZiIngredientFactory1 implements BaoZiIngredientFactory
{
@Override
public Veggies createVeggies()
{
return new Cabbage(); // A1
}
@Override
public Meat createMeat()
{
return new Pork(); // B1
}
}
~~~
~~~
package abstractFactory;
// 具体工厂2生产的白菜牛肉包子
public class BaoZiIngredientFactory2 implements BaoZiIngredientFactory
{
@Override
public Veggies createVeggies()
{
return new Cabbage(); // A1
}
@Override
public Meat createMeat()
{
return new Beaf(); // B2
}
}
~~~
~~~
package abstractFactory;
// 具体工厂3生产的青椒牛肉包子
public class BaoZiIngredientFactory3 implements BaoZiIngredientFactory
{
@Override
public Veggies createVeggies()
{
return new GreenPepper(); // A2
}
@Override
public Meat createMeat()
{
return new Beaf(); // B2
}
}
~~~
~~~
package abstractFactory;
//具体工厂4生产的青椒猪肉包子
public class BaoZiIngredientFactory4 implements BaoZiIngredientFactory
{
@Override
public Veggies createVeggies()
{
return new GreenPepper(); // A2
}
@Override
public Meat createMeat()
{
return new Pork(); // B1
}
}
~~~
### 一个Client
~~~
package abstractFactory;
// Client即包子,聚合两个抽象产品,关联工厂接口
public class BaoZi
{
String name;
// 一个包子就是一个"a family of products"
// 一个包子由分布在两类抽象产品中的三个具体产品构成
Veggies veggies; // A类产品-蔬菜馅
Meat meat; // B类产品-肉馅
BaoZiIngredientFactory factory; // 工厂接口
public BaoZi()
{
// 构造函数都不做什么事
}
public void setIngredientFactory(BaoZiIngredientFactory factory)
{
this.factory = factory;
}
public void makeBaoZi()
{
prepare(); // 准备原材料
steam(); // 蒸30分钟
setName(veggies.toString() + meat.toString() + "包子");
}
void prepare()
{
veggies = factory.createVeggies();
meat = factory.createMeat();
System.out.println("Preparing " + veggies.toString() + "," + meat.toString());
}
void steam()
{
System.out.println("Steam for 30 minutes");
}
void setName(String name)
{
this.name = name;
}
String getName()
{
return name;
}
public String toString()
{
StringBuffer result = new StringBuffer();
result.append("---- " + name + " ----\n");
if (veggies != null)
{
result.append(veggies);
result.append("馅 + ");
}
if (meat != null)
{
result.append(meat);
result.append("馅\n");
}
return result.toString();
}
}
~~~
### 一个封装Client类的简单工厂
抽象工厂可以结合简单工厂,当然也可以结合工厂方法模式,用来封装new Client( ) 的过程。简单工厂的本质是:依据传入的参数,决定生产,然后return哪一个new BaoZi(产品族, a family of products)
~~~
package abstractFactory;
public class BaoZiStore
{
protected BaoZi createBaoZi(String baoZiName)
{
BaoZi baoZi = new BaoZi();
BaoZiIngredientFactory factory = null;
if(baoZiName.equals("白菜猪肉"))
{
factory = new BaoZiIngredientFactory1();
baoZi.setIngredientFactory(factory);
}
else if(baoZiName.equals("白菜牛肉"))
{
factory = new BaoZiIngredientFactory2();
baoZi.setIngredientFactory(factory);
}
else if(baoZiName.equals("青椒牛肉"))
{
factory = new BaoZiIngredientFactory3();
baoZi.setIngredientFactory(factory);
}
else if(baoZiName.equals("青椒猪肉"))
{
factory = new BaoZiIngredientFactory4();
baoZi.setIngredientFactory(factory);
}
return baoZi;
}
public BaoZi orderBaoZi(String baoZiName)
{
BaoZi baoZi = createBaoZi(baoZiName);
baoZi.makeBaoZi();
return baoZi;
}
}
~~~
### 一个Main类
~~~
package abstractFactory;
public class Main
{
public static void main(String[] args)
{
BaoZiStore baoZiStore = new BaoZiStore();
BaoZi baoZi = null;
baoZi = baoZiStore.orderBaoZi("白菜猪肉");
System.out.println(baoZi);
baoZi = baoZiStore.orderBaoZi("白菜牛肉");
System.out.println(baoZi);
baoZi = baoZiStore.orderBaoZi("青椒牛肉");
System.out.println(baoZi);
baoZi = baoZiStore.orderBaoZi("青椒猪肉");
System.out.println(baoZi);
}
}
~~~
# 运行结果
直接从eclipse复制过来
~~~
Preparing 白菜,猪肉
Steam for 30 minutes
---- 白菜猪肉包子 ----
白菜馅 + 猪肉馅
Preparing 白菜,牛肉
Steam for 30 minutes
---- 白菜牛肉包子 ----
白菜馅 + 牛肉馅
Preparing 青椒,牛肉
Steam for 30 minutes
---- 青椒牛肉包子 ----
青椒馅 + 牛肉馅
Preparing 青椒,猪肉
Steam for 30 minutes
---- 青椒猪肉包子 ----
青椒馅 + 猪肉馅
~~~
# 抽象工厂模式和工厂方法模式的差别
**代码层面:**
工厂方法模式:工厂抽象类,几个工厂子类继承这个抽象类,工厂子类new Product() ,任务完成。
抽象工厂模式:工厂接口,几个工厂子类实现这个接口,工厂子类new 很多 Products(),但是任务还没完。
我们需要的是”a family of Products”(产品族)。此时需要引入新的角色,Client。**这个Client关联工厂子类,把工厂子类new出来的所有Products聚合起来,形成一个产品族**。然后再把这个产品族,看成”一个大产品“(我的代码中的包子)。为了让这个”大产品(包子)的new的过程“不至于直接暴露在Main类中,把这个大产品封装在一个简单工厂里面(或者*HF* 封装在工厂方法模式里面)。此时任务才完成~~
**需求层面:**
直接引用*HF* 里面的原话,原话已经不能够再简练了。。。
Abstract Factory: Remember me, Abstract Factory, and use me whenever you have families of products you need to create and you want to make sure your clients create products that belong together.
Factory Method: And I’m Factory Method; use me to decouple your client code from the concrete classes you need to instantiate, or if you know ahead of time all the concrete classes you are going to need. To use me, just subclass me implement my factory method!
深入研究设计模式,[猛戳这里(推荐新窗口打开)~](http://blog.csdn.net/u013390476/article/details/50333763)