一、为什么要有使用简单工厂模式

工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。

在面向对象领域中,遵循开闭原则,即:软件中的对象(类、模块、函数等)对扩展是开放的,对修改是封闭的。这意味着一个实体是允许在不改变它的源代码的前提下变更它的行为。

工厂模式是一种典型的 解耦模式 ,可以有效降低耦合度;同时,它依靠抽象架构,把实例化的任务交给实现类完成, 扩展性 好;同时,对于复杂的对象,很适合使用工厂模式创建。

工厂模式可以分为三类

  • 简单工厂模式(Simple Factory)
  • 工厂方法模式(Factory Method)
  • 抽象工厂模式(Abstract Factory)

先从最简单的简单工厂模式开始学习

二、简单工厂模式

简单工厂模式,主要包含3个要素:

  • Factory: 工厂类,简单工厂的核心部分,负责实现创建所有产品的内部逻辑,工厂类可以直接被外界调用。
  • Product:抽象类产品,他是工厂类创建对象的父类,封装了各种产品对象的公有方法,它的引用将提高系统的灵活性,是的工厂类中只需要定义一个通用的工厂方法就可以创建其子对象。
  • CurrentProduct:具体产品类,它就是工厂模式创建的目标。
    简单工厂模式UML

创建product接口

public class HuaWei implements Product {
    @Override
    public void create() {
        System.out.println("Create HuaWei!");
    }
}

创建Apple、HuaWei类,实现Product接口

public class Apple implements Product {
    @Override
    public void create() {
        System.out.println("Create Apple!");
    }
}
public class HuaWei implements Product {
    @Override
    public void create() {
        System.out.println("Create HuaWei!");
    }
}

创建ProductFactory方法实现工厂生产,并创建main方法实现案例

public class ProductFactory {

    public Product getProduct(String productType) {
        if (productType == null) {
            return null;
        }

        if (productType.equals("Apple")) {
            return new Apple();
        } else if (productType.equals("HuaWei")) {
            return new HuaWei();
        }
        return null;
    }

    public static void main(String[] args) {
        ProductFactory productFactory = new ProductFactory();

        Product apple = productFactory.getProduct("Apple");
        Product huaWei = productFactory.getProduct("HuaWei");

        apple.create();
        huaWei.create();

    }
}

输出结果如下:

Create Apple!
Create HuaWei!

简单工厂模式,如果新增了一个Product实现类,则需要对工厂类重新修改,违反了开闭原则,因此需要在基础上进行优化。

三、工厂方法模式

简单工厂,是直接在同一个工厂中,生产出不同的产品实例对象,当产品需要增加时,则需要重新修改工厂内的方法。

工厂方法模式,是把生产不同类实例的功能,交给不同的工厂生产。

在简单工厂基础上,新增了一个抽象工厂对象
工厂方法模式UML图

以上Product、Apple、HuaWei类都不变

新增IFactory接口

public interface IFactory {

    Product creatProduct();
}

创建Apple、HuaWei工厂

public class AppleFactory implements IFactory{
    @Override
    public Product creatProduct() {
        return new Apple();
    }
    
}
public class HuaWeiFactory implements IFactory {

    @Override
    public Product creatProduct() {
        return new HuaWei();
    }
}

测试

public class main {

    public static void main(String[] args) {
        // 想要Apple产品,则使用Apple工厂
        IFactory appleFactory = new AppleFactory();
        Product apple = appleFactory.creatProduct();
        apple.create();

        // 想要HuaWei产品,则使用HuaWei工厂
        IFactory huaweiFactory = new HuaWeiFactory();
        Product huawei = huaweiFactory.creatProduct();
        huawei.create();
        
    }
}

输出结果

Create Apple!
Create HuaWei!

工厂方法模式使用场景

在以下情况下可以使用工厂方法模式:

  • 一个类不知道它所需要的对象的类:在工厂方法模式中,客户端不需要知道具体产品类的类名,只需要知道所对应的工厂即可,具体的产品对象由具体工厂类创建;客户端需要知道创建具体产品的工厂类。
  • 一个类通过其子类来指定创建哪个对象:在工厂方法模式中,对于抽象工厂类只需要提供一个创建产品的接口,而由其子类来确定具体要创建的对象,利用面向对象的多态性和里氏代换原则,在程序运行时,子类对象将覆盖父类对象,从而使得系统更容易扩展。

使用场景

  • 日志记录器:记录可能记录到本地硬盘、系统事件、远程服务器等,用户可以选择记录日志到什么地方。
  • 数据库访问,当用户不知道最后系统采用哪一类数据库,以及数据库可能有变化时。
  • 设计一个连接服务器的框架,需要三个协议,“POP3”、“IMAP”、“HTTP”,可以把这三个作为产品类,共同实现一个接口。

工厂方法模式总结

优点

  • 一个调用者想创建一个对象,只要知道其名称就可以了。
  • 扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。
  • 屏蔽产品的具体实现,调用者只关心产品的接口。

缺点

每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。

四、抽象工厂模式

既然工厂方法模式每次有新产品的时候,都需要新建一个工厂,那是否可以直接在原有工厂的基础上,新增一个方法多生产一个产品呢?
通过这样的方式去实现,也就是形成了抽象工厂模式

抽象工厂UML

以上Product、Apple、HuaWei类都不变

创建AbstractFactory 同时实现Apple和Huawei的创建

public interface AbstractFactory {

    Apple createApple();

    HuaWei createHuawei();
}

创建SuperFactory类,可以拥有生产2种产品的能力

public class SuperFactory implements AbstractFactory {
    @Override
    public Apple createApple() {
        return new Apple();
    }

    @Override
    public HuaWei createHuawei() {
        return new HuaWei();
    }
}

测试

public class AbstractFactoryTest {
    public static void main(String[] args) {
        AbstractFactory superFactory = new SuperFactory();
        Product apple = superFactory.createApple();
        Product huawei = superFactory.createHuawei();
        apple.create();
        huawei.create();
    }
}

输出结果如下

Create Apple!
Create HuaWei!

抽象工厂模式的应用场景

抽象工厂模式最早的应用是用于创建属于不同操作系统的视窗构件。如 Java 的 AWT 中的 Button 和 Text 等构件在 Windows 和 UNIX 中的本地实现是不同的。

通常应用于以下场景:

  • 当需要创建的对象是一系列相互关联或相互依赖的产品族时,如电器工厂中的电视机、洗衣机、空调等。
  • 系统中有多个产品族,但每次只使用其中的某一族产品。如有人只喜欢穿某一个品牌的衣服和鞋。
  • 系统中提供了产品的类库,且所有产品的接口相同,客户端不依赖产品实例的创建细节和内部结构。

五、反射+工厂模式

以上的不论是 简单工厂模式、工厂方法模式以及抽象工厂模式,在创造一个产品类的时候,都需要重新修改工厂方法或者是创建一个新的工厂方法,这样的情况,还是不容易扩展的,每当有新的产品类出现时,就要修改工厂或者创建新的工厂类。

能否可以不创建新的工厂类,也不修改原有的工厂方法,根据传入的需求产品,就可以根据需求创造出对应的产品类呢?

JDK1.8之后引入的Reflect反射机制,可以实现这个请求。

要做修改,首先要知道Reflect反射的基本概念,以下不赘述反射。

反射+工厂模式,只需要创建3个对象:

  • BeanFactory :负责根据传入的对象类路径生产出对应的类实例。
  • Product 父类:拥有子产品的共同特征
  • 实例产品类 :Product的具体实现

BeanFactory类图

以上Product、Apple、HuaWei类都不变

创建一个新的工厂类BeanFactory

package com.wenan.design.factory.reflectfactory;

/**
 * 描述:    BeanFactory 根据反射机制,根据传入的类路径创建类的实例
 */
public class BeanFactory {
    private Object object;

    /**
     * 构造方法,根据传入的类路径获取类的实例
     * @param s 类的路径
     * @throws ClassNotFoundException
     * @throws IllegalAccessException
     * @throws InstantiationException
     */
    BeanFactory(String s) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        Class<?> aClass = Class.forName(s);
        Object o = aClass.newInstance();
        this.object = o;
    }

    public Object getObject() {
        return object;
    }

    public void setObject(Object object) {
        this.object = object;
    }
}

测试

public class ReflectTest {

    public static void main(String[] args) throws IllegalAccessException, InstantiationException, ClassNotFoundException {
        //  Apple的类路径
        String appleClassPath="com.wenan.design.factory.simplefactory.Apple";
        //  HuaWei的的类路径
        String huaweiClassPath="com.wenan.design.factory.simplefactory.HuaWei";
		
        BeanFactory appleFactory= new BeanFactory(appleClassPath);
        Product apple = (Product) appleFactory.getObject();
        apple.create();

        BeanFactory huaweiFactory = new BeanFactory(huaweiClassPath);
        Product huawei  = (Product)huaweiFactory.getObject();
        huawei.create();
    }
}

Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐