浅谈设计模式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将没有任何区别。

至此,抽象类结束。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,042评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 89,996评论 2 384
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,674评论 0 345
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,340评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,404评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,749评论 1 289
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,902评论 3 405
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,662评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,110评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,451评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,577评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,258评论 4 328
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,848评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,726评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,952评论 1 264
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,271评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,452评论 2 348

推荐阅读更多精彩内容