【Java必备】Java工厂模式(Spring BeanFactory)

工厂模式的概览图

简单工厂模式

简单工厂模式又叫做静态工厂方法(StaticFactory Method)模式,但不属于23种GOF设计模式之一。简单工厂模式的实质是由一个工厂类根据传入的参数,决定应该创建哪一个产品类对象。用户无需关心创建的过程,只需使用即可。

写一个简单的Car汽车接口,有不同的实现子类

// 汽车接口
public interface Car {

    void run();
}

// 汽车产品一:实现类--BMW
public class Bmw implements Car{

    @Override
    public void run() {
        System.out.println("----宝马车启动----");
    }
}

// 汽车产品二:实现类--Benz
public class Benz implements Car{
    @Override
    public void run() {
        System.out.println("----奔驰车启动----");
    }
}

// 汽车产品三:实现类--Audi
。。。

静态工厂类:

public class CarStaticFactory {

    public static Car getCar(String carName){
        if (carName.equals("BMW")){
            return new Bmw();
        }else if (carName.equals("Benz")){
            return new Benz();
        }
        return null;
    }
}

测试类:

public class Test {
    public static void main(String[] args) {
        Car car = CarStaticFactory.getCar("BMW");
        car.run();
    }
}

输出:

  • 优点:把对类的创建初始化全都交给一个工厂类来完成,用户无需关心创建的过程,降低耦合,将创建与使用分离。
  • 缺点:违背了设计模式的“开闭原则”,如果后期需要增加更多的产品类,则必须对工厂类做修改。

改进:为了解决 每增加一个产品,就得修改工厂类,增加一个else if分支,可通过反射创建实例

工厂类增加一个通过类全路径去获取实例(反射)

public class CarStaticFactory {

    public static Car getCar(String carName){
        if (carName.equals("BMW")){
            return new Bmw();
        }else if (carName.equals("Benz")){
            return new Benz();
        }
        return null;
    }

    // 通过反射获取类实例
    public static Car getCarByReflect(String classPath){
        Car car = null;
        try {
            Class clazz = Class.forName(classPath);
            //创建对象
            car = (Car) clazz.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return car;
    }
}

测试类,当然这里类路径可以放在配置文件中,通过配置文件读取

public class Test {
    public static void main(String[] args) {

        // 静态工厂
//        Car car = CarStaticFactory.getCar("BMW");
        Car car = CarStaticFactory.getCarByReflect("com.example.demo.factory.Bmw");
        car.run();

    }
}

输出:

但这样还是有问题,类的全路径写耦合在代码使用中了,可配置在文件中。

再次改造:增加配置文件,读取配置文件获取对应的类路径变量,再反射创建实例

创建一个配置文件 applicationContext.properties文件

bmw=com.example.demo.factory.Bmw
benz=com.example.demo.factory.Benz

改造工厂类,读取配置文件获取类路径,再通过反射创建实例:

/**
 * @description: 模拟bean工厂类
 * @author: stwen_gan
 * @date: 
 **/
public class BeanFactory {
    /**
     * 通过properties类获取配置文件中的配置
     */
    private static Properties properties = new Properties();

    static {
        try {
            //1. 获得IO输入流
            InputStream inputStream = BeanFactory.class.getClassLoader().getResourceAsStream("applicationContext.properties");
            //2. 加载流
            properties.load(inputStream);
            //3. 关闭流
            inputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static Car getCarByName(String beanName){
        Car car = null;
        try {
            Class clazz = Class.forName(properties.getProperty(beanName));
            //创建对象
            car = (Car) clazz.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return car;
    }
}

测试:

public class Test {
    public static void main(String[] args) {

        // 静态工厂
//        Car car = CarStaticFactory.getCar("BMW");
//        Car car = CarStaticFactory.getCarByReflect("com.example.demo.factory.Bmw");
//        car.run();

        Car bmw =BeanFactory.getCarByName("bmw");
        Car benz =BeanFactory.getCarByName("benz");
        bmw.run();
        benz.run();

    }
}

输出:

通过上述的一步步改造,我们实现了一个通用的工厂模式,有点类似Spring容器的实现思路

其实,Spring在启动时通过xml、JavaConfig、注解扫描等方式注册bean,我们需要某个bean实例时,就可以通过调用getBean方法从ApplicationContext中获取容器的bean对象。Spring中的BeanFactory就是简单工厂模式的体现,根据传入一个唯一的标识来获得Bean对象,所以说,虽然简单的静态工厂模式有缺陷,但是正因为它简单方便,可通过一定的改造,在某些场景更实用方便。

工厂方法模式

利用多态的特性,通过实现同一个工厂接口来创建不同的工厂子类型,将 if-else 分支去掉。

将上面的工厂类变为为一个接口或抽象类,由具体不同类型的工厂子类去实现,当需要增加不同的产品实现类时,同时只需要增加多一个工厂子类即可

// 抽象接口
public interface ICarFactory {

    Car getCarByFactory();
}

// bmw 工厂子类 (某一类型的工厂,只生产bmw车型)
public class BmwFactory implements ICarFactory{
    @Override
    public Car getCarByFactory() {
        return new Bmw();
    }
}

// benz 工厂子类 (某一类型的工厂,只生产benz车型)
public class BenzFactory implements ICarFactory{
    @Override
    public Car getCarByFactory() {
        return new Benz();
    }
}

// ....

测试类:

public class Test {
    public static void main(String[] args) {

//        // 静态工厂
//        Car car = CarStaticFactory.getCar("BMW");
//        car.run();

        // 工厂方法
        Car car = new BmwFactory().getCarByFactory();
        car.run();
        
    }
}

输出:

  • 优点:利用工厂模式可以降低程序的耦合性,为后期的维护修改提供了很大的便利。将选择实现类、创建对象统一管理和控制,从而将调用者跟我们的实现类解耦。
  • 缺点:会导致工厂类对象的创建耦合到了代码使用方中。每增加一个汽车类,同时也要增加多一个相应的汽车工厂实现类。

抽象工厂模式 

定义:为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类。

  抽象工厂与工厂方法的区别,就在于产品簇的问题,上面只是能创建汽车这一种产品,假如这时我们需要多了一种产品(如飞机),这时候怎么办呢?可以在抽象工厂里增加一个生产飞机的方法,然后在每个具体工厂子类也增加相应的实现方法,这样的话,缺点很明显,需要修改抽象工厂和具体工厂子类。

  抽象工厂模式是工厂方法模式的升级版本,他用来创建一组相关或者相互依赖的对象。他与工厂方法模式的区别就在于,工厂方法模式针对的是一个产品等级结构;而抽象工厂模式则是针对的多个产品等级结构。在编程中,通常一个产品结构,表现为一个接口或者抽象类,也就是说,工厂方法模式提供的所有产品都是衍生自同一个接口或抽象类,而抽象工厂模式所提供的产品则是衍生自不同的接口或抽象类。

/**
 * @description: 抽象工厂--可生产不同产品组产品
 * @author: stwen_gan
 * @date: 
 **/
public interface Factory {

    Car getCarByFactory();

    Plane getPlaneByFactory();

    // 其他产品组。。。
}

// 工厂一:可生产宝马汽车和客机
public class FactoryOne implements Factory{

    @Override
    public Car getCarByFactory() {
        return new Bmw();
    }

    @Override
    public Plane getPlaneByFactory() {
        return new AirPlane();
    }
}

// 工厂二:可生产奔驰汽车和战斗机
public class FactoryTwo implements Factory{

    @Override
    public Car getCarByFactory() {
        return new Benz();
    }

    @Override
    public Plane getPlaneByFactory() {
        return new BattlePlane();
    }
}

测试类:

public class Test {
    public static void main(String[] args) {

        // 抽象工厂
        Car car1 = new FactoryOne().getCarByFactory();
        car1.run();
        Plane plane1 = new FactoryOne().getPlaneByFactory();
        plane1.fly();

        Car car2 = new FactoryOne().getCarByFactory();
        car2.run();
        Plane plane2 = new FactoryOne().getPlaneByFactory();
        plane2.fly();

    }
}

输出:

总结

  • 简单工厂 :用来生产同一等级结构中的任意产品,(不支持拓展增加产品)。
  • 工厂方法 :用来生产同一等级结构中的固定产品,(支持拓展增加产品) 。
  • 抽象工厂 :用来生产不同产品族的全部产品,(不支持拓展增加产品;支持增加产品族)。

实际使用中,需要根据具体的业务场景选择。

 

史上最强Tomcat8性能优化

阿里巴巴为什么能抗住90秒100亿?--服务端高并发分布式架构演进之路

B2B电商平台--ChinaPay银联电子支付功能

学会Zookeeper分布式锁,让面试官对你刮目相看

SpringCloud电商秒杀微服务-Redisson分布式锁方案

查看更多好文,进入公众号--撩我--往期精彩

一只 有深度 有灵魂 的公众号0.0

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值