【设计模式】之工厂模式

工厂方法设计模式

软件系统经常不断变化,而且不稳定。我们必须考虑对象和关系的松耦合。
松耦合是软件设计时一个非常重要的特性,可以帮助系统不做或者做很少的变更就能扩展新功能。

工厂方法设计模式提供了一种将一个对象实例作为一个对象工厂的方式。
工厂可以根据提供给它的参数返回类层次结构中可能的几个类中一个类实例。

工厂设计模式属于创造型模式。工厂设计模式分为简单工厂工厂方法抽象工厂设计模式

  • 简单工厂设计模式:简单工厂并不是严格意义上的设计模式。它更多的是一种用于封装对象实例化过程的编程技术。
  • 工厂方法设计模式:定义了一个创建对象的接口,决定哪个类实例化,工厂方法允许将类的实例化延迟到子类。
  • 抽象工厂设计模式:提供一个接口,用于创建相关或依赖对象,而无需指定它们。

工厂设计模式的好处

  • 客户端不需要知道它创建的每一个子类。仅仅需要一个抽象类或者接口的引用和工厂对象。
  • 工厂封装了对象的创建。当创建过程非常复杂的时候,这是非常有用的。

简单工厂模式

Spice Digital Inc.是印度最大的智能手机制造商之一。他们是在印度市场生产和销售智能手机的先锋。
目前,他们拥有两种成功的产品 SpiceFire 和 SpiceBolt。 productMobile() 方法可以根据它们的型号生产不同的手机。
现在的实现是这样的:


public SpiceMobile produceMobile(String model) {
        SpiceMobile mobile = null;

        if (model.equalsIgnoreCase("SpiceBolt")) {
            mobile = new SpicePlus();
        } else if (model.equalsIgnoreCase("SpiceFire")) {
            mobile = new SpiceBolt();
        }
        mobile.prepare();
        mobile.bundle();
        mobile.label();

        return mobile;
}

SpiceMobile 的实现:

public abstract class SpiceMobile {
    public abstract void prepare();
    public abstract void bundle();
    public abstract void label();
}

public class SpiceFire extends SpiceMobile {
    @Override
    public void prepare() {
    }

    @Override
    public void bundle() {
    }

    @Override
    public void label() {
    }
}

public class SpiceBolt extends SpiceMobile {

    @Override
    public void prepare() {
    }

    @Override
    public void bundle() {
    }

    @Override
    public void label() {
    }
}

上述实现方式存在的问题:

  • 上述实现目前工作的很欢快。但是,在某个时间点,这家公司想要发行一个新的产品到市场的时候,他们必须去修改 produceMobile() 方法的代码。
  • 上述设计扩展性是非常差的,封闭改造。
  • 每当添加新产品时,都会增加代码重构的复杂性。

工厂设计模式示例

上面的例子在生产手机方面确认是很有效。但是,我们也提出了一些问题。现在我们给上面的需求添加一些复杂的功能。
Spice Digital Inc. 公司现在决定发展全球业务了。它们想扩展在伦敦和纽约的业务。根据市场需求,在伦敦只会生产 SpiceBolt、SpiceFire,而在纽约则会生产 SpiceFire和SpicePlus。
现在,用例图就变得复杂了,我们看一下下面使用工厂设计模式的类图吧:

工厂设计模式类图

e org.byron4j.cookbook.designpattern.factory;

public abstract class SpiceMobile {
public double price;

public double getPrice() {
    return price;
}

public void setPrice(double price) {
    this.price = price;
}

public abstract void prepare();
public abstract void bundle();
public abstract void label();

}


现在来创建3种不同的Spice Mobile实现。为了方便演示,SpiceBolt、SpiceFire 和 SpicePlus 这三个实现类都是一样的代码,就不全部展示了。


#### SpiceBolt.java

```java

package org.byron4j.cookbook.designpattern.factory;

public class SpiceBolt extends  SpiceMobile {
    @Override
    public void prepare() {

    }

    @Override
    public void bundle() {

    }

    @Override
    public void label() {

    }
}

MobileFactory.java


package org.byron4j.cookbook.designpattern.factory;

public abstract  class MobileFactory {
    public abstract SpiceMobile constructMobile(String model);

    /**
     * 这可以算是模板方法了...^_*
     * @param model
     * @return
     */
    public SpiceMobile produceMobile(String model){
        SpiceMobile spiceMobile = constructMobile(model);
        spiceMobile.prepare();
        spiceMobile.bundle();
        spiceMobile.label();
        return spiceMobile;
    }
}

LondonMobileFactory.java


package org.byron4j.cookbook.designpattern.factory;

public class LondonMobileFactory extends  MobileFactory {
    @Override
    public SpiceMobile constructMobile(String model) {
        SpiceMobile spiceMobile = null;

        if( "SpiceFire".equalsIgnoreCase(model) ){
            spiceMobile = new SpicePlus();
            spiceMobile.setPrice(300);
        }else if("SpiceBolt".equalsIgnoreCase(model)){
            spiceMobile = new SpiceBolt();
            spiceMobile.setPrice(400);
        }
        
        return spiceMobile;
    }
}


NYMobileFactory.java

package org.byron4j.cookbook.designpattern.factory;

public class NYMobileFactory extends  MobileFactory {
    @Override
    public SpiceMobile constructMobile(String model) {
        SpiceMobile spiceMobile = null;

        if( "SpiceFire".equalsIgnoreCase(model) ){
            spiceMobile = new SpicePlus();
            spiceMobile.setPrice(200);
        }else if("SpiceMono".equalsIgnoreCase(model)){
            spiceMobile = new SpiceFire();
            spiceMobile.setPrice(200);
        }

        return spiceMobile;
    }
}


FactoryTest.java

package org.byron4j.cookbook.designpattern;

import org.byron4j.cookbook.designpattern.factory.LondonMobileFactory;
import org.byron4j.cookbook.designpattern.factory.MobileFactory;
import org.byron4j.cookbook.designpattern.factory.NYMobileFactory;
import org.byron4j.cookbook.designpattern.factory.SpiceMobile;
import org.junit.Test;

public class FactoryTest {

    @Test
    public void test() {
        MobileFactory factory = new LondonMobileFactory();
        SpiceMobile spiceMobile1 = factory.produceMobile("SpiceFire");
        System.out.println(spiceMobile1);

        MobileFactory factory2 = new NYMobileFactory();
        SpiceMobile spiceMobile2 = factory2.produceMobile("SpiceMono");
        System.out.println(spiceMobile2);

    }
}


工厂方法模式的好处

工厂方法模式增强了可扩展性,现在如果Spice Digital Inc. 公司需要在其他城市扩展业务,则只需要新增加一个新的工厂实现即可。

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

推荐阅读更多精彩内容

  • 在面向对象编程中, 最通常的方法是一个new操作符产生一个对象实例,new操作符就是用来构造对象实例的。但是在一些...
    聂叼叼阅读 3,962评论 2 16
  • 工厂模式是最常用的一类创建型设计模式,之前一直以为工厂模式只是23中设计模式中的一种,重新了解才知道这个模式还要细...
    晨鸣code阅读 1,262评论 0 6
  • 写在第一句的话:设计模式虽好,可不要贪杯哦,不要为了套设计模式而写设计模式,别把简单的问题复杂化。 刚接触...
    星期三不上班阅读 375评论 2 0
  • 这是我设计模式系列的第一篇总结。首先讲一下为什么需要使用工厂设计模式?我们平时正常开发编码的时候创建对象有几种方式...
    超人有点忙阅读 335评论 0 0
  • 设计模式概述 在学习面向对象七大设计原则时需要注意以下几点:a) 高内聚、低耦合和单一职能的“冲突”实际上,这两者...
    彦帧阅读 3,733评论 0 14