设计模式之 工厂模式

来源:互联网 发布:javascript案例教程 编辑:程序博客网 时间:2024/06/10 07:56

工厂模式就好比将java中创建具体对象的方式带入了工厂时代,你可以轻松方便地构造对象实例,而不必关心构造对象实例的细节和复杂过程。 它是基于为创建对象提供了过渡接口,以便将创建对象的具体过程屏蔽起来,达到提高灵活性的目的。


工厂模式分类

工厂模式中一般分为三类,分别是简单工厂模式、工厂方法模式和抽象工厂模式。 我们举一个例子来说明这三种模式

假设现在苹果公司没有工厂,那么我们要一部 iphone6s 手机,那么他就要根据客户的需求单独生产一个 iphone6s 手机,来满足客户的需求。

现在苹果公司有了简单工厂(简单工厂模式),那么公司就不用为客户单独生产手机,工厂可以直接生产 iphone6s 手机,这时不仅可以生产 iphone6s 还可以生产其他型号,只要有型号说明就可以生产出对应的产品。

接下来随着苹果公司产量的大规模提升,每个型号的差异也有了很大的区别,一个工厂无法满足如此大量的需求,这时候就引进了多工厂(工厂方法模式),这时候总工厂(一个抽象类)负责生产所有 iphone 系列通用部分,各个子工厂负责生产对应型号的部分。

接下来随着客户的要求越来越高,iphone 必须配置蓝宝石玻璃。通过寻找合作厂商(interface接口)与各个子厂合作(实现这个接口),合作厂商来提供不同型号 iphone 的不同规格的蓝宝石玻璃


简单工厂模式

简单工厂模式又称为静态工厂方法模式,它属于类创建型模式。在简单工厂模式中,可以根据参数的不同返回不同类的实例。简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。我们根据 iphone 那个例子看看简答工厂模式中生产 iphone 的工厂的样子

/** * 手机生产Iphone的简单工厂类 * * @since 16/5/16. */public class IPhoneFactory {    public IPhone create(String type) {        if (type.equalsIgnoreCase("6s")) {            return new IPhone6s();        } else if (type.equalsIgnoreCase("6")) {            return new IPhone6();        } else if (type.equalsIgnoreCase("5s")) {            return new IPhone5s();        } else {            return null;        }    }}

我们可以看到,通过传入型号就可以生产相对应的 iphone 手机,然后我们来看一下 iphone 手机的类是什么样子,通过代码看一下被创建的实例通常都具有共同的父类这句话的意思

/** * @since 16/5/16 */public class IPhone {    protected String name; //iphone的不同型号名字    public IPhone(){        packaging();        prepare();    }    public void packaging() {        System.out.println("组装手机零部件... ");    }    public void prepare() {        System.out.println("将手机装盒包装,贴防伪标签");    }    public String getName(){        return name;    }}class IPhone6s extends IPhone {    public IPhone6s() {        super();        this.name = "Iphone6s";    }}class IPhone6 extends IPhone {    public IPhone6() {        super();        this.name = "Iphone6";    }}class IPhone5s extends IPhone {    public IPhone5s() {        super();        this.name = "Iphone5s";    }}

我们可以看到,iphone 的不同型号都是继承自一个 Iphone 这个父类,这样就通过多态的方式得到不同的型号的名字,然后我们看一下客户 user 是如何通过商店购买到 iphone 手机这个过程的

/** * 手机商店 * * @since 16/5/16. */public class IPhoneStore {    private IPhoneFactory factory = new IPhoneFactory();    public IPhone sellIPhone(String type) {        IPhone iPhone = factory.create(type);        return iPhone;    }}/** * 买IPhone的用户,直接去Iphone销售点(IPhoneStore)购买 * * @since 16/5/16 */public class User {    private IPhoneStore store;    public static void main(String[] args) {        new User().buy("6");    }    public void buy(String type) {        store = new IPhoneStore();        IPhone iPhone = store.sellIPhone(type);        System.out.println("用户购买到"+iPhone.getName()) ;    }}

User 客户通过简单的告诉商店型号需求,然后商店就会将工厂生产出对应的型号交给客户,这个流程就完成了,我们来看一下运行的效果

这里写图片描述

由于工厂类 IPhoneFactory 集中了所有产品创建逻辑,一旦不能正常工作,整个系统都要受到影响。同时我们要知道使用简单工厂模式将会增加系统中类的个数(以后还要添加 Iphone7 等类… ),在一定程序上增加了系统的复杂度和理解难度,这样也就存在着系统扩展困难的问题,一旦添加新产品就不得不修改工厂逻辑,在产品类型较多时,有可能造成工厂逻辑过于复杂,不利于系统的扩展和维护。

根据上述的优缺点,我们分析出简单工厂模式适用场景

  • 工厂类负责创建的对象比较少
    由于创建的对象较少,不会造成工厂方法中的业务逻辑太过复杂。

  • 客户端只知道传入工厂类的参数,对于如何创建对象不关心
    客户端既不需要关心创建细节,甚至连类名都不需要记住,只需要知道类型所对应的参数。

工厂方法模式

工厂方法模式又称为多态工厂模式,它属于类创建型模式。在工厂方法模式中,工厂父类负责定义创建产品对象的公共接口(抽象类),而工厂子类则负责生成具体的产品对象,这样做的目的是将产品类的实例化操作延迟到工厂子类中完成,即通过工厂子类来确定究竟应该实例化哪一个具体产品类。我们再通过 Iphone 那个例子来看看工厂方法模式
首先 Iphone 系列类不变和上面一样

/** * @since 16/5/16 */public class IPhone {    protected String name; //iphone的不同型号名字    public IPhone() {    }    public void packaging() {        System.out.println("组装手机零部件... ");    }    public void prepare() {        System.out.println("将手机装盒包装,贴防伪标签");    }    public String getName() {        return name;    }}class IPhone6s extends IPhone {    public IPhone6s() {        super();        this.name = "Iphone6s";    }}class IPhone6 extends IPhone {    public IPhone6() {        super();        this.name = "Iphone6";    }}class IPhone5s extends IPhone {    public IPhone5s() {        super();        this.name = "Iphone5s";    }}

我们看一下抽象的工厂方法类

/** * 抽象类工厂 * * @since 16/5/16 */public abstract class IphoneStore {    public abstract IPhone createIphone(String type);    public IPhone sellIphone(String type) {        IPhone iPhone = createIphone(type);        iPhone.prepare();        iPhone.packaging();        return iPhone;    }}

这里我们将创建 Iphone 这个流程交给子工厂去处理,这样就可以灵活的添加子类工厂中特有的元素,比如我们下面的这个中国的苹果工厂就可以自定义贴上 “中国红” 的标签,如果都放在一个工厂中,那么类似中国工厂还有德国、英国、法国等等,会出现大量的 if 判断… 然我们看一下这个中国工厂(其他子工厂类似)

/** * 中国生产Iphone6的厂子 * * @since 16/5/16 */public class ChinaIphoneStore extends IphoneStore {    public ChinaIphoneStore() {        //自定义一些特有内容        System.out.println("贴上中国红标志 made in China");    }    @Override    public IPhone createIphone(String type) {        IPhone iPhone = null;        if ("6s".equals(type)) {            iPhone = new IPhone6s();        } else if ("6".equals(type)) {            iPhone = new IPhone6();        } else if ("5s".equals(type)) {            iPhone = new IPhone5s();        }        return iPhone;    }}

这里最重要的就是父类的 create 方法是抽象的,需要交给子类进行自定义处理,然后我们看一下User是如何买到这个Iphone的

/** * 买IPhone的用户 * * @since 16/5/16 */public class User {    IphoneStore cStore;    public static void main(String[] args) {        new User().buy("5s");    }    /**     * 买一种型号的iphone     *     * @param type     */    public void buy(String type) {        cStore = new ChinaIphoneStore();        IPhone iPhone = cStore.sellIphone(type);        System.out.println("用户购买到" + iPhone.getName());    }}

这样就可以从中国的工厂买到 Iphone 的手机了,然后我们看一下执行的效果
这里写图片描述

在工厂方法模式中,工厂方法用来创建客户所需要的产品,同时还向客户隐藏了哪种具体产品类将被实例化这一细节,用户只需要关心所需产品对应的工厂,无须关心创建细节,甚至无须知道具体产品类的类名。
另一个优点是在系统中加入新产品时,无须修改抽象工厂和抽象产品提供的接口,无须修改客户端,也无须修改其他的具体工厂和具体产品,而只要添加一个具体工厂和具体产品就可以了。这样,系统的可扩展性也就变得非常好,完全符合“开闭原则”。

那么任何方式都是有利有弊的,采用工厂方法模式添加新产品时,需要编写新的具体产品类,而且还要提供与之对应的具体工厂类,系统中类的个数将成对增加,在一定程度上增加了系统的复杂度,有更多的类需要编译和运行,会给系统带来一些额外的开销

根据上述的优缺点,我们分析出简单工厂模式适用场景

  • 一个类不知道它所需要的对象的类
    在工厂方法模式中,客户端不需要知道具体产品类的类名,只需要知道所对应的工厂即可,具体的产品对象由具体工厂类创建;客户端需要知道创建具体产品的工厂类。

  • 一个类通过其子类来指定创建哪个对象
    在工厂方法模式中,对于抽象工厂类只需要提供一个创建产品的接口,而由其子类来确定具体要创建的对象,利用面向对象的多态性在程序运行时,子类覆盖父类对象,从而使得系统更容易扩展。

抽象工厂模式

抽象工厂为创建一组相关或相互依赖的对象提供一个接口,而无需指定他们的具体类。抽象工厂模式又称为 Kit 模式,属于对象创建型模式。我们接的说我们的 iphone 例子,前面说到 iphone 要嵌入蓝宝石玻璃,于是我们新建一个提供蓝宝石玻璃的接口

/** * @since 16/5/16 */public interface GlassFactory {    /**     * 生产蓝宝石玻璃     *     * @return     */    public Glass createGlass();}

我们看一下配套的蓝宝石玻璃类

/** * @since 16/5/16 */public class Glass {    public Glass() {        System.out.println("手机配备相应型号的蓝宝石玻璃");    }}

然后在我们的中国厂商中加入这个合作Glass厂商(实现这个接口),通过代码我们看一下

/** * 中国生产Iphone6的厂子 * * @since 16/5/16 */public class ChinaIphoneStore extends IphoneStore implements GlassFactory{    public ChinaIphoneStore() {        forkChina();    }    @Override    public IPhone createIphone(String type) {        IPhone iPhone = null;        if ("6s".equals(type)) {            iPhone = new IPhone6s();        } else if ("6".equals(type)) {            iPhone = new IPhone6();        } else if ("5s".equals(type)) {            iPhone = new IPhone5s();        }        return iPhone;    }    public void forkChina(){        System.out.println("贴上中国红标志 made in China");        System.out.println("使用"+createGlass()+"做玻璃");    }    @Override    public Glass createGlass() {        return new Glass();    }}

然后运行 User 类,我们可以看到下面这个效果

贴上中国红标志 made in China
手机配备相应型号的蓝宝石玻璃
使用Glass@71662a95做玻璃
将手机装盒包装,贴防伪标签
组装手机零部件…
用户购买到Iphone5s

我们可以看到,应用抽象工厂模式可以实现高内聚低耦合的设计目的,抽象工厂模式其实是工厂方法模式的一种扩展,应用抽象工厂模式可以创建一系列的产品(产品族),而不是像工厂方法模式中的只能创建一种产品。抽象工厂模式最大的缺点就是对产品族的扩展非常困难,如果要添加一个新的 “红宝石玻璃厂商” 的话,看看我们的改动会有多大吧… 首先要在Factory接口中声明新方法

  HongBaoshiGlass createGlass()

  然后在所有现有的工厂实现类中分别实现这个新的 createGlass() 方法,如果工厂类有很多,改动的地方也会很多的… 违反了开闭原则,并且作为契约的接口修改了,其他所有和接口有关的代码可能都要改。

总体来说,每一个模式都是针对一定问题的解决方案,工厂方法模式针对的是一个产品等级结构,而抽象工厂模式针对的是多个产品等级结构。有多少个产品等级结构,就会在工厂角色中发现多少个工厂方法。每一个产品等级结构中有多少个具体的产品,就有多少个产品族,也就会在工厂等级结构中发现多少个具体工厂

那么关于工厂模式的设计方式就总结到这里

0 0
原创粉丝点击