HeadFirst设计模式4-工厂模式

1.为啥需要工厂模式(why)

在我平常的工作中我们往往会写下如下的代码。

public Pizza orderPizza(String type) {
        Pizza pizza = new Pizza();
        //以下是变化的部分
        if (type.equals("chesss")) {
            pizza = new ChessPizza();
        } else if (type.equals("clam")) {
            pizza = new CalmPizza();
        }
        pizza.bake();
        return pizza;
    }

以上代码的问题在于我们要增加种类的时候,需要打开这段代码进行修改。这样造成系统难以维护,也更容易犯错。

我们对拓展开放,对修改关闭。通常这种情况下,应该抽象出变化的部分。

2.如何实现工厂模式。

  1. 我们首先实现一个简单工厂模式
  • 抽象出变化的部分,就是工厂
public class SimplePIizzaFactory {
    public Pizza createPizza(String type) {
        Pizza pizza = null;
        if (type.equals("ChessPizza")) {
            pizza = new ChessPizza();
        } else if (type.equals("CalmPizza")) {
            pizza = new CalmPizza();
        }
        return pizza;
    }
}
  • 调用的时候只需要用简单工厂生成就行
public class PizzaStroe {
    SimplePIizzaFactory simplePIizzaFactory;

    public PizzaStroe(SimplePIizzaFactory simplePIizzaFactory) {
        this.simplePIizzaFactory = simplePIizzaFactory;
    }

    public Pizza orderPizza(String type) {
        Pizza pizza =simplePIizzaFactory.createPizza(type);
        pizza.bake();
        return pizza;
    }
}

上面这样做的好处在于抽象出变化的部分,供其他部分调用 。另外,当我们需要修改的时候,只需要修改工厂类,其他的部分就不需要变动。

  1. 工厂模式(真正意义上的工厂模式)

工厂方法模式定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。

  • 定义一个基本的工厂基类和它的子工厂类
//定义抽象的Pizza类
public abstract class Pizza {

    public String name;

    public ArrayList<String> ingredent=new ArrayList<>();

    void prepare(){
        System.out.println("Prepare: "+name);
        for(int i=0;i<ingredent.size();i++){
            System.out.print(ingredent.get(i)+" ");
        }

    }
    void bake(){
        System.out.println("Pizza is baking");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public ArrayList<String> getIngredent() {
        return ingredent;
    }

    public void setIngredent(ArrayList<String> ingredent) {
        this.ingredent = ingredent;
    }
}
public abstract class PizzaStroe {

    public Pizza orderPizza(String type) {
        //不用管子类是什么
        Pizza pizza = createPizza(type);
        pizza.bake();
        return pizza;
    }

    //定义抽象方法,由子类来实现
    public abstract Pizza createPizza(String type);
}
//武汉的工厂类,生产出武汉style的Pizza
public class WuhanPizzaStore extends PizzaStroe {
    @Override
    public Pizza createPizza(String type) {
        Pizza pizza = null;
        if (type.equals("CalmPizza")) {
            pizza = new CalmPizza();
            pizza.ingredent.add("WuhanStyle");
        } else if (type.equals("ChessPizza")) {
            pizza = new ChessPizza();
            pizza.ingredent.add("WuhanStyle");
        }
        return pizza;
    }
}
//北京的工厂类,生产出北京style的Pizza
public class BeijingPizzaStore extends PizzaStroe {
    @Override
    public Pizza createPizza(String type) {
        Pizza pizza = null;
        if (type.equals("CalmPizza")) {
            pizza = new CalmPizza();
            pizza.ingredent.add("BeijingStyle");
        } else if (type.equals("ChessPizza")) {
            pizza = new ChessPizza();
            pizza.ingredent.add("BeijingStyle");
        }
        return pizza;
    }
}
  • 当我们需要Pizza的时候,只需要用那个工厂类就可以构造出那种风格的Pizza
public class PizzaTest {
    public static void main(String[] args) {
        PizzaStroe beijingPizzaStore=new BeijingPizzaStore();
        PizzaStroe wuhanPizzaStore=new WuhanPizzaStore();
        Pizza pizza1=beijingPizzaStore.orderPizza("CalmPizza");
        Pizza pizza2=wuhanPizzaStore.orderPizza("CalmPizza");
        System.out.println(pizza1.getName());
        System.out.println(pizza2.getName());

    }
}

来看下类图的关系

factorypattern.png

  简单工厂与工厂方法的区别:简单工厂把全部的事情在一个地方都处理完了,然而工厂方法却是创建一个框架,让子类决定如何实现。
简单工厂的做法,可以将对象的创建封装起来,但是简单工厂不具备工厂方法的弹性,因为简单工厂不能变更正在创建的产品。

  1. 抽象工厂模式
    首先给出定义

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

  • 首先我们定义抽象接口
public interface PropertyFactory {
    public String getName();
    public ArrayList<String> getIngredent();
}

在实际的场合中,抽象接口里面的抽象方法都是返回某个想要创建的抽象类,我这里比较简单,直接返回字符串和集合。之所以称为抽象工厂,我们从这里就可以看出来。通过抽象的方法,返回你希望得到的类的基类。

  • 我们构造抽象工厂类的实现类
public class CalmPropertyFactory implements PropertyFactory {

    @Override
    public String getName() {
        return "NewCalmPizza";
    }

    @Override
    public ArrayList<String> getIngredent() {
        ArrayList<String> arrayList=new ArrayList<>();
        arrayList.add("Newcalm");
        return arrayList;
    }
}

public class ChessPropertyFactory implements PropertyFactory {
    @Override
    public String getName() {
        return "NewChessPizza";
    }

    @Override
    public ArrayList<String> getIngredent() {
        ArrayList<String> arrayList = new ArrayList<>();
        arrayList.add("Newchess");
        return arrayList;
    }
}

那么此时的Pizza的子类应该如此构造

public class CalmPizza extends Pizza {
    PropertyFactory propertyFactory;
    public CalmPizza(PropertyFactory propertyFactory) {
        this.propertyFactory=propertyFactory;
        name=propertyFactory.getName();
        ingredent=propertyFactory.getIngredent();
    }
}

直接用对应的原料工厂来构造。
来看下类图。


abstractFactory.png
  1. 个人总结(conclusion)
      通过以上的描述,我们很容易明白工厂模式,也很容易区分简单工厂和工厂模式的区别(即构造类是在一个工厂类里面统一构造,还是通过子类的工厂方法来构造)。但是令人迷惑的是工厂模式与抽象工厂模式有什么区别。区别如下:

抽象工厂的每个方法实际上看起来都像是工厂方法,每个方法都被声明成抽象。而子类的方法来覆盖这些方法来创建某些对象。注意到,这里的子类是想要构造类的成分,就像我上面的写的name和ingredent成员。Pizza的子类只需要依赖依赖这些成分工厂类,例如ChessPropertyFactory ,就能构造出对象。重点突出抽象,是因为它有一个总的抽象接口,实现它的子类负责构造对象的成分,总而构成对象。

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

推荐阅读更多精彩内容

  • 设计模式汇总 一、基础知识 1. 设计模式概述 定义:设计模式(Design Pattern)是一套被反复使用、多...
    MinoyJet阅读 3,884评论 1 15
  • 设计模式基本原则 开放-封闭原则(OCP),是说软件实体(类、模块、函数等等)应该可以拓展,但是不可修改。开-闭原...
    西山薄凉阅读 3,739评论 3 13
  • 1 场景问题# 1.1 选择组装电脑的配件## 举个生活中常见的例子——组装电脑,我们在组装电脑的时候,通常需要选...
    七寸知架构阅读 4,244评论 6 66
  • 一、设计模式的分类 总体来说设计模式分为三大类: 创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者...
    RamboLI阅读 739评论 0 1
  • 世间事,繁杂多,不必自扰。人生路,艰苦难,踏雪寻梅。 ...
    天蓝色的海岸阅读 253评论 1 0