是时候弄一套开分店的标准了---抽象工厂

cover

前情提要

上集讲到, 小光(利用原型模式)Copy了光谷店的模式, 成功开张了创业街分店.

现在两家分店都运营得不错, 小光闲暇之时, 又陷入了思考(思考是个好习惯). 琢磨着, 这次开分店, 我是完全clone了光谷店的那一套, 然后修改了一些个属性(例如分店名字什么的). 但是, 以后小光热干面的发展, 还会开出很多分店呢, 而且没家分店可能不仅仅是名字不一样, 还有一些诸如饮料杯上的地址什么的也会不一样, clone起来是很方便, 但是万一哪次忘了改属性了, 就麻烦了.

想到着, 小光心想, 是时候制定一套开分店的标准流程/方式了.

所有示例源码已经上传到Github, 戳这里

分店都有什么

根据现有的经验, 小光很快总结出来了目前按照他的方式开一家热干面店基本包括的一系列东西:

  1. 店铺
  2. 收银台
  3. 杯具餐具
  4. 热干面流程
  5. 饮料机套路
  6. 活动策略
  7. ...

为便于区分讲解, 我们以前三个为例.

建立开分店的标准方式

制定每项东西标准

本着良好的面向接口编程思维, 小光照例给这些东西制定了一些标准(接口).

门面:

public interface Store {

    // 地址
    String getAddress();

    // 店铺名
    String getName();
}

收银台:

public interface Checkstand {

    // 银行账户
    String getAccount();
}
public interface Tableware {

    // 标签
    String getLabel();
}

统一配置生产

接下来, 小光要做的就是想着统一下每个分店开店的标准, 既要避免开分店时别遗漏了什么, 也能根据不同分店的配置开出不一样的分店. (开闭原则)

开分店的标准如下:

public interface CompanyFactory {

    Store createStore();

    Checkstand createCheckstand();

    Tableware createTableware();
}

按照这个方式开分店

好的, 让我们来试下按照这个标准套路来开出SBI创业街分店.

先实现创业街分店的Store, Checkstand和Tableware:

public class SbiStore implements Store {

    @Override
    public String getAddress() {
        return "关山创业街";
    }

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

public class SbiCheckStand implements Checkstand {

    @Override
    public String getAccount() {
        return "招商银行:620123131231233";
    }
}

public class SbiTableware implements Tableware {
    @Override
    public String getLabel() {
        return "SBI";
    }
}

然后, 实现一个SBI的专属工厂来生成这些东西:

public class SbiCompanyFactory implements CompanyFactory {
    @Override
    public Store createStore() {
        return new SbiStore();
    }

    @Override
    public Checkstand createCheckstand() {
        return new SbiCheckStand();
    }

    @Override
    public Tableware createTableware() {
        return new SbiTableware();
    }
}

让我们利用SBI工厂生成的东西组建一个分店吧:

public class XiaoGuang {

    public static void main(String[] args) {

        CompanyFactory factory = new SbiCompanyFactory();

        // 来根据factory生产出来的东西构建一个分店:
        Company sbiCompany = new Company(factory.createStore(), factory.createCheckstand(), factory.createTableware());

        System.out.println(sbiCompany);
    }
}

结果:

分店{地址:关山创业街, 名字:SBI店, 收银账户:招商银行:620123131231233, 杯具餐具标签:SBI}

不负众望啊, 创建出来SBI店了.

以后我们就可以根据这种方式开分店了

例如, 如果想开一家花山软件新城店, 按照上面开创业街店的方式:

  1. 实现花山店的店铺 HuashanStore.
  2. 实现花山店的收银台 HuashanCheckStand.
  3. 实现花山店的餐具 HuashanTableware.
  4. 实现生产花山店的这些东西的工厂 HuashanCompanyFactory.

代码就不一一贴了, 完整代码戳这里.

来看下怎么开出花山分店:

// 创建Huashan工厂
factory = new HuashanCompanyFactory();

// 根据factory生产出来的东西构建花山店:
Company huashanCompany = new Company(factory.createStore(), factory.createCheckstand(), factory.createTableware());

System.out.println(huashanCompany);

结果:

分店{地址:花山软件新城, 名字:花山店, 收银账户:建设银行:62610000000000, 杯具餐具标签:HS}

好的, 花山店创建完毕.

故事之后

在这次建立创建分店的标准中, 小光一直想做就是: 确定分店的开设方式标准, 避免修改原有的分店产品, 方便扩展开出新的分店.

这个实际上就是我们屡次提到的开闭原则的思想, 即对修改关闭(不修改原有的), 对扩展开放(方便扩展出新的产品/实例).

惯例, 我们来梳理下类之间的关系:

没错, 这个就是我们今天的主角 --- 抽象工厂模式.

抽象工厂
提供一个创建一系列相关或互相依赖的对象的接口, 而无需指定它们的具体实现.

在本例中这个接口就是CompanyFactory, 它创建了一系列相关的对象(Store, Checkstand, Tableware), 并且这些对象并非具体实现(也是接口). 具体的对象实例是由实现了CompanyFactory接口的HuashanCompanyFactory, SbiCompanyFactory来创建的.

扩展阅读一

到目前为止, 算上这个, 我们提到了三种工厂:

  1. 小光热干面提供饮料了 --- 简单工厂
  2. 光氏饮品升级了 --- 工厂方法
  3. 是时候弄一套开分店的标准了 --- 抽象工厂

那么这三者有什么区别呢?

我们首先来对比下三者的类图:


简单工厂
实际上我们可以理解为是一种编程习惯, 将类似对象的初始化放下一个地方, 便于管理.
它提供了一个工厂(表妹), 来根据不同的指令(drinkType)来生产不同的饮料产品(橙汁, 可乐, 酸梅汤).
相对简单, 适用于要创建类似(实现同一接口的)的产品, 且产品种类不多, 扩展可能性不大的情况. 当需要增加一中饮料时, 我们需要修改工厂(表妹)的实现, 增加drinkType的对应实现.

工厂方法
顾名思义, 有一个工厂, 工厂(饮料机)里有那么一个方法(定义了一个创建对象的接口makeDrink), 可以生产产品(Drink). 由实现了这个工厂方法的类来决定具体生产出什么产品(可以是可乐, 橙汁, 奶茶等).

相比于简单工厂, 工厂方法有良好的扩展性, 当我们需要增加一种饮料时, 不需要去修改工厂, 只需扩展一个新的工厂, 实现其工厂方法, 提供新的饮料即可.

这实际上就是典型的, 通过继承/实现, 来达成了对修改关闭, 对扩展开放的效果.

另外, 从简单工厂到工厂方法, 我们也可以理解为是一次Switch Statements的重构.

对于"Switch Statements的重构", 有兴趣的同学可以参看<<重构--改善既有代码的设计>>一书的3.10节. 那是一本好书, 2010年的时候华为的一位技术经理推荐给我的, 感谢他.

另外, 并不是我们以后遇到Switch就要想着改造, 遇到简单工厂就想着用工厂方法...还需根据实际情况取用合适的.

抽象工厂
同样, 从名字中, 我们大致能了解, 抽象工厂描述的一个抽象的工厂, 其可以生产一系列的相关的或是互相依赖的产品.

抽象工厂和工厂方法有很多类似之处, 都是创建产品, 都是通过继承/实现, 来达成了对修改关闭, 对扩展开放的效果.

然而, 抽象工厂相较于工厂方法, 它的重点, 是它解决的是一个产品族(相关的, 或是互相依赖的产品们)的创建问题, 而非仅仅是一类产品.

以本故事来说, 工厂方法是用来创建一类产品, 通过他创建出来的都是饮料. 而抽象工厂是用来创建一系列产品, 包括店铺, 收银台, 餐具等, 这些产品是相关的, 都是一个分店所需要的.

打个比方, 如果我有一个轮胎工厂, 我生产的东西都是轮胎, 只是规格不同, 我就可以使用工厂方法; 如果我是一个汽车工厂, 我生产汽车, 它需要轮胎, 车架, 发动机... 那么我就应用使用抽象工厂.

扩展阅读二

前文, 原型模式我们讲到, 原型工厂, 会经常跟工厂一起用. 那么它一般会与哪种工厂一起用呢, 没错, 就是我们今天说的抽象工厂.

为什么呢?
我们回过头来看下, 我们抽象工厂创建的过程, 是不是创建了很多对象啊. 是的, 抽象工厂如果生产的产品系列很多的话, 我们会发现我们会创建很多很多的对象(产品), 而这些对象有的时候是可能一样的, 有可能是很类似的.

例如, 我们的分店工厂创建了收银台(Checkstand), 这个不同的分店的收银台可能都是一样的, 稍微有点不同可能是仅仅是账户不一样, 我们没有必要去重新创建一个.

回想下, 原型模式的使用 --- 使用clone的方式来快速创建一个新的(与原型对象实例一致的)对象实例. 这种方法可以避免我们屡次复杂的创建.

我们当前的Checkstand创建可能相对简单, 想象下, 如果Checkstand足够复杂的时候, clone将会是很有用的.

具体的实现, 大家可以私下去改造下本例代码, 融合下原型模式, 体验下.


OK, 创建出开分店的标准了, 小光想着, 以后开分店都不用我亲力亲为的...哈哈.

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

推荐阅读更多精彩内容