设计模式之工厂模式

工厂模式(FactoryPattern)

工厂模式是一种常见的创建型的设计模式,是将对象的创建交给所谓的“工厂”进行,降低了客户端与创建的对象的耦合,也就是解耦。
工厂模式又分为简单工厂模式(SimpleFactoryPattern)、工厂方法模式(FactoryMethodPattern)和抽象工厂模式(AbstractFactoryPattern)。

如何使用工厂模式,用农民养殖的道理告诉你。
作为一名生活在农村的勤劳农民,如果想吃鸡的话,一般的话都是自己家饲养的,这就好比我们需要某个类的实例就必须用new Object()创建出来。
虽然这样也比较简单,但是有时我们需要的多了,自己家饲养的鸡可就不够了,而且有时我们并不一定要吃鸡,还要吃鸭或者吃鹅,这时候就比较麻烦了。
相关的代码就需要修改,凡是和创建对象相关的代码片段都要修改,这是个巨大的工作量。
那么简单工厂模式就出场了。

简单工厂模式(SimpleFactoryPattern)

作为农民的你很有经济头脑,在农村想吃鸡直接在家饲养就可以了,但是生活在城市里的人们可没有条件进行直接饲养,于是你想把鸡卖给城里人。
于是你在家开始了养殖之路。

首先你养的是家禽(Fowl),具体的有鸡(Chicken)和鸭(Duck)。

Fowl.java

public interface Fowl {
    void yell();
}

Chicken.java

public class Chicken implements Fowl {
    @Override
    public void yell() {
        System.out.println("我是一只鸡");
    }
}

Duck.java

public class Duck implements Fowl {
    @Override
    public void yell() {
        System.out.println("我是一只鸭");
    }
}

作为在家开展养殖副业的你,发展的肯定顺风顺水。但是之前养殖都是小打小闹,在自家院子里还能养,随着规模的扩大,就需开一个养殖厂进行机械化养殖,这样方便管理而且更高效。

MyFactory.java

public class MyFactory {
    public static Fowl getFowl(String name) {
        Fowl fowl = null;
        if (name.equals("Chicken"))
            fowl = new Chicken();
        else if (name.equals("Duck"))
            fowl = new Duck();
        return fowl;
    }
}

通过这个养殖厂,养殖鸡和鸭就方便多了,直接告诉工厂想要什么样的家禽,工厂就直接给你提供完成的产品。

Client.java

public class Client {
    public static void main(String[] args) {
        Chicken chicken = (Chicken) MyFactory.getFowl("Chicken");
        chicken.yell();
        Duck duck = (Duck) MyFactory.getFowl("Duck");
        duck.yell();
    }
}

这样和我们创建对象也一样,直接告诉工厂我们想要什么样的对象,工厂直接就返回我们想要的对象。

我是一只鸡
我是一只鸭

UML图:

整个系统主要包括以下角色:

  • Fowl-抽象产品
  • ChickenDuck-具体产品
  • MyFactory-工厂

优点:

  • 通过工厂创建对象,我们可以免于直接接触对象创建;这就像之前家庭作坊式的养殖,任何事情都是自己亲自做,现在有养殖场了,如果你想要什么,直接吩咐下去工厂里的工人就给解决了,多省事啊。
  • 对于一些配置参数比较多的对象创建,可以将具体对象的创建在工厂内完成,我们只需记住与之对应的代号或者参数即可;比如家庭作坊养殖时,饲料需要各种饲料搭配,这都要自己去干,现在是养殖场而且是机械化的养殖场,喂什么饲料直接从饲料器里出来,直接养出吃某种饲料的鸡或鸭。
  • 配置参数的较多的对象在传入参数时,可以采用配置文件的形式,这样就可以在不改变代码的情况下,更换创建的对象;就好比工厂拿到配置文件里的饲料配方,给你提供吃这种饲料的鸡或者鸭。

到目前为止,作为一个将家庭作坊养殖发展到小型机械化养殖场的农民企业家,你似乎感觉还不错,但是你的能力实在是太强了,规模又扩大。但是,你发现在一个养殖场里既养鸡又养鸭,会产生很多不便,鸡和鸭的饲养方式不一样、生活习性不一样。之后又想养鹅,这时候你的养殖场真的是不堪重负啊,隐患严重啊。
总结一下缺点:

  • 工厂类中集中所有产品的逻辑,一旦有一环节出现问题,整个系统都有可能出现问题。
  • 如果要增加一个新产品,就需要修改现有的工厂逻辑,增加了系统的复杂度。
  • 当增加的产品越来越多时,整个系统的逻辑会过于复杂,不利于扩展和维护。

工厂方法模式(FactoryMethodPattern)

在上一节中,农民企业家的你遇到了发展的难题-怎么在扩大规模的同时解决效率问题。
这时候你灵光一闪,你想到了可以将鸡和鸭分开养殖,就是建立两个养殖场,如果以后还要再养殖其他种类的家禽,直接再建个养殖场,这样就避免了整个系统的不稳定以及难扩展和维护。

现在你决定在原来养鸡和鸭的基础上,再养鹅。

Goose.java

public class Goose extends Fowl {
    @Override
    public void yell() {
        System.out.println("我是一只鹅");
    }
}

但是现在你不能再像之前那样讲所有的家禽都饲养在一个养殖厂里,你需根据不同的种类建立响应的养殖场。
首先建立个养殖场的模式,即一个养殖场的接口或者抽象类。

Factory.java

public interface Factory {
    Fowl createFowl();
}

然后根据养殖的种类建立响应的工厂。

ChickenFactory.java

public class ChickenFactory implements Factory {
    @Override
    public Fowl createFowl() {
        return new Chicken();
    }
}

DuckFactory.java

public class DuckFactory implements Factory {
    @Override
    public Fowl createFowl() {
        return new Duck();
    }
}

GooseFactory.java

public class GooseFactory implements Factory {
    @Override
    public Fowl createFowl() {
        return new Goose();
    }
}

现在各个工厂已经建立了,你的客户想要什么家禽,直接去相应的养殖场去拿。

Client.java

public class Client {
    public static void main(String[] args) {
        Factory chickenFactory = new ChickenFactory();
        Chicken chicken = (Chicken) chickenFactory.createFowl();
        chicken.yell();
        Factory duckFactory = new DuckFactory();
        Duck duck = (Duck) duckFactory.createFowl();
        duck.yell();
        Factory gooseFactory = new GooseFactory();
        Goose goose = (Goose) gooseFactory.createFowl();
        goose.yell();
    }
}

UML图:

整个系统主要包括以下角色:

  • Fowl-抽象产品
  • ChickenDuckGoose-具体产品
  • Factory-抽象工厂
  • ChickenFactory.javaDuckFactory.javaGooseFactory.java-具体工厂

优点:

  • 对象的创建交给相应的工厂,完全不需要知道创建的过程;想要哪种家禽直接去相应的养殖场去取,没有必要理会家禽是怎么饲养的。
  • 每个产品在生产过程中有着不同的创建逻辑,因此可以在各自的工厂内部实现;每种家禽的饲养技术不一样,因此在各自的养殖场中可以根据特点进行改变。
  • 以后每增加一个种类,只需增加一个具体产品和相应的具体工厂。

虽然现在已经解决养殖规模扩大带来的问题,但是立志要作为一名成功的企业家,必须要有远见的眼光。这种模式还是有些问题:

  • 由于每增加一个种类要增加一个具体产品和相应的具体工厂,虽然这样避免了工厂内部逻辑随着产品增加复杂度增加的问题,但是产品种类多了整个系统的类的数量也增加了,会给系统带来负担。
  • 由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度,且在实现时可能需要用到DOM、反射等技术,增加了系统的实现难度。

抽象工厂模式(AbstractFactoryPattern)

通过工厂方法模式,你解决了之前的问题,但是创业的过程是艰辛的,你有遇到问题了。
你的家禽养殖场越办越好,赚的钱越来越多,你想着要把养殖场的规模在扩大一些,于是你又开办了养猪场和养牛场,而且还想在隔壁镇上复制你的商业模式。
但是你的养殖规模扩大了,可是你发现你的利润降低了,于是你仔细研究了以下你的管理模式,发现两个问题:

  • 开办一个新的养殖场需要各种审批手续,耗时太长。
  • 你打算养殖一个品种,就开办一个养殖场,虽然这样能够方便每个养殖场的管理,但是所有养殖场管理和之间的配合很麻烦。
    其实这就是上节提到的工厂方法模式的弊端。

经过你的深思熟虑,于是你做出了深化改革的决定。首先将目前所有的产品分成两个系列,家禽(Fowl)和家畜(Livestock),然后将所有养殖场整合成一个大的养殖场,建立一个养殖场的管理模板(AbstractFactory)。

Livestock.java

public abstract class Livestock {
    public abstract void yell();
}

Pig.java

public class Pig extends Livestock {
    @Override
    public void yell() {
        System.out.println("我是一头猪");
    }
}

Cattle.java

public class Cattle extends Livestock {
    @Override
    public void yell() {
        System.out.println("我是一头牛");
    }
}

AbstractFactory.java

public interface AbstractFactory {
    Fowl createFowl();
    Livestock createLivestock();
}

抽象工厂AbstractFactory设计这样让你感觉到似乎不合理,因为一个大型养殖场里不可能养殖一种家禽和家畜,要怎样设计才能更合理呢,于是你又灵光一闪。

AbstractFactory.java

public interface AbstractFactory {
    Fowl createFowl(String name);
    Livestock createLivestock(String name);
}

设计成这样,你是不是感觉很熟悉啊,对的这就是简单工厂模式。加入你在每个工厂里面一类产品只生产一种,原来的设计完全可以胜任,但是你要在工厂里面一类产品要生产多种,可以结合原来的简单工厂模式。

MyFactory.java

public class MyFactory implements AbstractFactory {
    @Override
    public Fowl createFowl(String name) {
        Fowl fowl = null;
        if (name.equals("chicken")) fowl = new Chicken();
        else if (name.equals("duck")) fowl = new Duck();
        else if (name.equals("goose")) fowl = new Goose();
        return fowl;
    }

    @Override
    public Livestock createLivestock(String name) {
        Livestock livestock = null;
        if (name.equals("pig")) livestock = new Pig();
        else if (name.equals("cattle")) livestock = new Cattle();
        return livestock;
    }
}

Client.java

public class Client {
    public static void main(String[] args) {
        AbstractFactory myFactory = new MyFactory();
        Chicken chicken = (Chicken) myFactory.createFowl("chicken");
        chicken.yell();
        Duck duck = (Duck) myFactory.createFowl("duck");
        duck.yell();
        Cattle cattle = (Cattle) myFactory.createLivestock("cattle");
        cattle.yell();
    }
}

现在你可以把你的商业模式开到任何一个镇上了。

UML图:

整个系统主要包括以下角色:

  • FowlLivestock-抽象产品
  • ChickenDuckGooseCattlePig-具体产品
  • AbstractFactory-抽象工厂
  • MyFactory.java-具体工厂

目前这种模式确实不算是典型抽象工厂模式,而是通过简单工厂模式扩展的抽象工厂模式。

总结

我们梳理一下这三种工厂模式之间的关系。

简单工厂模式与工厂方法模式:

  • 对象的创建都是在具体工厂中进行的,但是工厂方法模式的具体工厂是通过接口实现或者类继承,工厂具有可扩展性;
  • 同时工厂方法模式中的一个具体工厂只能创建一个对象,任何一个对象的创建逻辑的更改不会影响到其他对象的创建;
  • 如果工厂方法模式在创建对象时结合简单工厂模式,可以创建一类对象的多个对象。

工厂方法模式与抽象工厂模式:

  • 在工厂方法模式中每个具体工厂只能创建一个对象,而在抽象工厂模式中每个具体工厂可以创建多种对象;
  • 如果抽象工厂模式在创建对象时结合简单工厂模式,可以创建多类多个对象。

三者之间的关系:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值