简介

工厂模式:用工厂提供的方法代替了使用new创建对象的操作, 将创建对象统一管理和控制从而将调用者与实现类进行解耦,实现了创建者与调用者的分离。

工厂模式主要是为创建对象提供了接口。工厂模式按照《Java与模式》中的提法分为三类:

  • 简单工厂模式(Simple Factory)

  • 工厂方法模式(Factory Method)

  • 抽象工厂模式(Abstract Factory)

在什么样的情况下我们应该记得使用工厂模式呢?

大体有两点:

  • 1.在编码时不能预见需要创建哪种类的实例。

  • 2.系统不应依赖于产品类实例如何被创建、组合和表达的细节

//手机接口
public interface Phone {
    void name();
}
//小米手机
public class XiaomiPhone implements Phone{
    @Override
    public void name() {
        System.out.println("小米手机");
    }
}
//华为手机
public class HuaweiPhone implements Phone{
    @Override
    public void name() {
        System.out.println("华为手机");
    }
}
//客户端
public class Client {
    public static void main(String[] args) {
        //创建小米手机类
        Phone phone=new XiaomiPhone();
        phone.name();
        
        //创建华为手机类
        Phone phone2=new HuaweiPhone();
        phone2.name();
    }
}

简单(静态)工厂模式

UML

代码示例:

手机接口、小米手机、华为手机的代码跟上面的例子一致,增加了工厂类,并且对客户端代码进行修改

//生产手机的工厂
public class factory {
    public static final int TYPE_XM = 1;//小米
    public static final int TYPE_HW = 2;//华为
​
    //生产手机
    public static Phone make(Integer type){
        switch (type) {
            case TYPE_XM:
               return new XiaomiPhone();
            case TYPE_HW:
               return new HuaweiPhone();
            default:
                return null;
        }
    }
}
//客户端
public class Client {
    public static void main(String[] args) {
        //通过工厂创建对象
        Phone phone = factory.make(factory.TYPE_XM);
        phone.name();
    }
}

特点

  • 1 它是一个具体的类,非接口 抽象类。有一个重要的create()方法,利用if或者 switch创建产品并返回。

  • 2 create()方法通常是静态的,所以也称之为静态工厂。

缺点

  • 1 扩展性差,违反ocp原则(我想增加一种手机,除了新增一个手机产品类,还需要修改工厂类方法)

  • 2 不同的产品需要不同额外参数的时候 不支持。

简单(静态)工厂模式(反射)

利用反射Class.forName(clz.getName()).newInstance()实现的简单工厂,

特点

  • 它也是一个具体的类,非接口 抽象类。但它的create()方法,是利用反射机制生成对象返回,好处是增加一种产品时,不需要修改create()的代码。

缺点

  • 工厂模式本质是创建型模式,基于反射频繁的创建对象,这种方法是不可取的,所以这种这种写法很少见,能不用就不用。

  • 因为Class.forName(clz.getName()).newInstance()调用的是无参构造函数生成对象,它和new Object()是一样的性质,而工厂方法应该用于复杂对象的初始化 ,当需要调用有参的构造函数时便无能为力了,这样像为了工厂而工厂。

简单工厂模式的分析: 简单工厂模式把创建对象的能力交给工厂,客户端要想创建一个对象无需知道对象创建的内部细节,只需要声明对象的类型,通过工厂来获取我们想要的对象。工厂模式的缺点是违反ocp原则,例如我们要增加一个产品,那么需要修改原有的代码,也就是需要修改工厂类的判断逻辑,增加一层判断。

工厂方法模式

UML

示例讲解:

手机接口、小米手机、华为手机的代码跟上面的例子一致,增加了抽象工厂、生产小米手机的工厂、生产华为手机的工厂,并且对客户端代码进行修改

//生产手机的工厂接口
public interface factory {
    //提供生产手机的方法
    Phone make();   
}
//生产小米手机的具体工厂
public class XiaomiFactory implements factory{
    @Override
    public Phone make() {
        return new XiaomiPhone();
    }
}
//生产华为手机的具体工厂
public class HuaweiFactory implements factory{
    @Override
    public Phone make() {
        return new HuaweiPhone();
    }
}
//客户端
public class Client {
    public static void main(String[] args) {
        //通过小米工厂创建小米手机对象
        Phone phone = new XiaomiFactory().make();
        phone.name();
    }
}

工厂方法模式的分析

工厂方法模式解决了简单工厂模式出现的弊端,也就是满足了ocp原则,例如我们要增加一个产品,步骤就是编写一个产品类去实现产品接口,另外还需要编写一个该产品的工厂去实现抽象工厂,而不需要修改原有的代码,缺点就是每扩展一个产品就需要创建该产品类以及生产该产品的工厂类,会大大增加类的数量,结构复杂。

简单工厂模式和工厂方法模式的对比

如果从结构复杂度、代码复杂度、编程复杂度和管理上的复杂度来考虑,我们会使用简单工厂模式,而如果从设计原则来说,譬如我们不能违反ocp原则,那么就得选择工厂方法模式;虽然工厂方法模式更符合设计模式的思想和原则,但由于简单工厂模式比较简单,所以在实际业务中,会更多的使用简单工厂模式。

抽象工厂模式

UML

示例讲解:

手机接口、小米手机、华为手机的代码跟上面的例子一致,增加了路由器接口、小米路由器、华为路由器、抽象工厂、生产小米系列产品的工厂、生产华为系列产品的工厂,并且对客户端代码进行修改

//路由器接口
public interface Router {
    void name();
}
​
//小米路由器
public class XiaomiRouter implements Router{
    @Override
    public void name() {
        System.out.println("小米路由器");
    }
}
​
//华为路由器
public class HuaweiRouter implements Router{
    @Override
    public void name() {
        System.out.println("华为路由器");
    }
}
//抽象工厂
public interface factory {
​
    //生产手机
    Phone makePhone();
    
    //生产路由器
    Router makeRouter();
}
//小米工厂:生产小米手机、小米路由器
public class XiaomiFactory implements factory{
​
    @Override
    public Phone makePhone() {
        return new XiaomiPhone();
    }
​
    @Override
    public Router makeRouter() {
        return new XiaomiRouter();
    }
​
}
//华为工厂:生产华为手机、华为路由器
public class HuaweiFactory implements factory{
​
    @Override
    public Phone makePhone() {
        return new HuaweiPhone();
    }
​
    @Override
    public Router makeRouter() {
        return new HuaweiRouter();
    }
​
}
//客户端
public class Client {
    public static void main(String[] args) {
        System.out.println("==========小米系列产品========");
        //创建小米工厂
        factory f=new XiaomiFactory();
        //通过小米工厂创建小米手机
        Phone phone = f.makePhone();
        phone.name();
        //通过小米工厂创建小米路由器
        Router router = f.makeRouter();
        router.name();
    }
}

抽象工厂模式的分析

抽象工厂模式提供了一个创建一系列相关或者相互依赖对象的接口,无需指定它们具体的类,优点是将一个系列的产品统一到一起创建;缺点是规定了所有可能被创建的产品集合,产品族中扩展新的产品困难。

工厂方法模式与抽象工厂模式的区别

工厂方法模式只能生产一种类型的产品,但是支持同等级产品的扩展,例如上面的手机工厂,只能生产手机,而如果要生产其他产品,例如路由器,那么需要修改工厂类,违反ocp,如果进行的是同等级产品的扩展,例如要生产小米手机、华为手机等,不需要修改工厂类,只需要增加生产该等级产品的工厂子类即可,符合ocp。

而抽象工厂模式支持的是同一系列产品的创建,也就是同一产品族,例如小米系列产品,华为系列产品,抽象工厂模式解决了工厂方法模式只能创建一种类型产品的弊端,并且支持的是同一产品族的扩展。

应用场景

  • JDK中Calendar的getInstance方法就用到了简单工厂模式

  • Spring中的IOC容器也用到了工厂模式,把创建对象的能力都交给IOC容器,换句话说,我们要创建某个对象实例,只需要从spring工厂中拿即可。

在Spring中有两个最基本的工厂,BeanFactory和ApplicationContext。BeanFactory是Spring框架的基础设施,面向的是Spring本身,也就是用于创建Spring扩展的其他内容,如Spring Security、Spring JDBC等,而ApplicationContext这个工厂是面向开发者的,也就是应用上下文——配置文件等,开发者能够使用这个工厂实现自己的功能。