序
对于抽象工厂,我想可能只是因为带了“工厂”两个字,所以书上就把三个工厂给放一块了。抽象工厂只能说是工厂模式的进一步抽象化。原来工厂生产实际的产品,而抽象工厂则是给出一套规范,来指导具体的工厂建设——如果Java中能引入动态运行时制造的类的机制,我想抽象工厂就更好说明一些。
1、背景
这次说pizza可能更合适些,因为毕竟好像中餐里没有像pizza这种馅料模式固定,但是选材不同的菜品。做一张pizza需要蔬菜、火腿、酱汁三种食材。而每种食材又有不同的选择空间。比如浙江风味的pizza就可以选择:竹笋,金华火腿,耗油三种食材来做pizza。而东北地区就可以选用酸菜,哈尔滨火腿,大酱三种食材来做pizza。同样,为了规范制作流程,我们规定蔬菜、火腿、酱汁三种食材必须出现,但是具体用什么,因地制宜即可。
2、抽象模式
这个模式相对来说比前两个模式,形式上简单许多。给出抽象工厂接口——可以是抽象类,也可以是接口。抽象工厂中的函数用来创建实体。而子类根据自身限制,实现抽象工厂给出的,创建实体的接口。
看下代码:
public class Test3 {
}
abstract class VegetableBase
{
public String toString() {
return "VegetableBase";
}
}
class Vegetable1 extends VegetableBase
{
@Override
public String toString() {
return "vegetable1";
}
}
class Vegetable2 extends VegetableBase
{
@Override
public String toString() {
return "vegetable2";
}
}
abstract class SauceBase
{
@Override
public String toString() {
return "SauceBase";
}
}
class Sauce1 extends SauceBase
{
@Override
public String toString() {
return "Sauce1";
}
}
class Sauce2 extends SauceBase
{
@Override
public String toString() {
return "Sauce2";
}
}
abstract class MeatBase
{
@Override
public String toString() {
return "MeatBase";
}
}
class Meat1 extends MeatBase
{
@Override
public String toString() {
return "Meat1";
}
}
class Meat2 extends MeatBase
{
@Override
public String toString() {
return "Meat2";
}
}
//上面分别定义了蔬菜、肉、酱汁三种原料的抽象类和其具体子类
//工厂抽象类,根据地域不同,生成相应的原料.抽象类定义成接口也行。因为没有实体,因此定义成什么形式都可以
abstract class IngrediantFactory
{
abstract public VegetableBase createVegetable();
abstract public MeatBase createMeat();
abstract public SauceBase createSauce();
}
//根据地域,定义具体的原料工厂类
class Factory1 extends IngrediantFactory
{
@Override
public VegetableBase createVegetable() {
return new Vegetable1();
}
@Override
public MeatBase createMeat() {
return new Meat1();
}
@Override
public SauceBase createSauce() {
return new Sauce1();
}
}
//第二个具体的工厂
class Factory2 extends IngrediantFactory
{
@Override
public VegetableBase createVegetable() {
return new Vegetable2();
}
@Override
public MeatBase createMeat() {
return new Meat2();
}
@Override
public SauceBase createSauce() {
return new Sauce2();
}
}
//给出Pizza抽象类
abstract class Pizza
{
protected String name;
protected IngrediantFactory factory;
VegetableBase vegetable;
MeatBase meat;
SauceBase sauce;
abstract public void prepare();
//为了保证工艺不被破坏,定义为final类型,防止子类修改
final public void bake(){}
final public void box(){}
}
//具体子类,构建工厂。
//构造函数的参数要特别注意。因为已经区别了工厂,所以构造参数已经不
//能是抽象工厂类的类型,而应该是具体的原料类型。
//但是书上却使用IngredientFactory类型,此处感觉不合理。具体还要根据
//应用场景
class Pizza1 extends Pizza
{
public Pizza1(Factory1 factory) {
this.factory=factory;
}
@Override
public void prepare() {
this.vegetable=this.factory.createVegetable();
this.meat=this.factory.createMeat();
this.sauce=this.factory.createSauce();
}
}
class Pizza2 extends Pizza
{
public Pizza2(Factory2 factory) {
this.factory=factory;
}
@Override
public void prepare() {
this.vegetable=this.factory.createVegetable();
this.meat=this.factory.createMeat();
this.sauce=this.factory.createSauce();
}
}
解析一下代码:
1)程序首先分别构造了三种食材的抽象基类,并用这三个抽象基类,根据不同地域特征,进一步构造了对应的具体子类。作为原材料工厂。
2)然后,程序继续构造Pizza工厂对应的抽象基类和对应的子类。在Pizza的抽象工厂中,prepare(),即准备原材料方法由于地域的限制,所以抽象基类只定义接口,而具体实现留给了不同的子类来构造。
同时,注意到bake(),box()方法由母公司来控制,各个子公司不能修改,因此用final修饰,保证过程不会发生改变。
3)最后,考虑到不同地域的工厂有不同的原料供应,所以Pizza子类的构造函数的参数,需要制定出具体的原料工厂类型,如果仍然使用抽象基类,则子类Pizza1和子类Pizza2将没有任何区别。
至此,抽象类结束。