浅谈设计模式5——抽象工厂模式


对于抽象工厂,我想可能只是因为带了“工厂”两个字,所以书上就把三个工厂给放一块了。抽象工厂只能说是工厂模式的进一步抽象化。原来工厂生产实际的产品,而抽象工厂则是给出一套规范,来指导具体的工厂建设——如果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将没有任何区别。

至此,抽象类结束。

你可能感兴趣的:(浅谈设计模式5——抽象工厂模式)