设计模式之工厂模式

设计模式之工厂模式

简单工厂模式

提供一个方法用来获取对象的实例,用户无需关心具体实现,返回的类型可以是接口、抽象类或者具体的类

image-20201217105917486

具体实现如下:

工厂类

public class SimpleFactory {

    public static final String PINEAPPLE = "pineapple";
    public static final String APPLE = "apple";
    static Fruit getInstance(String fruitType) {
        if (APPLE.equals(fruitType)) {
            return new Apple();
        } else if (PINEAPPLE.equals(fruitType)) {
            return new Pineapple();
        } else {
            return null;
        }
    }

    public static void main(String[] args) {
        SimpleFactory.getInstance(APPLE);
        SimpleFactory.getInstance(PINEAPPLE);

    }
}
public class Apple extends Fruit {
    public Apple() {
        System.out.println("获得一个温带苹果");
    }
}
public
class Pineapple extends Fruit {
    public Pineapple() {
        System.out.println("获得一个热带菠萝");
    }
}

工厂类的getInstance方法根据传入的类型进行判断,然后返回创建好的对象实例,这样的工厂模式下有一个坏处就是每当增加一个新的类就得去修改工厂模式的代码。这个时候可以使用配置文件进行配置,免去修改工厂方法的源代码。在这里使用properties文件进行配置,因为使用方便简单。这里使用香蕉,以上实现的接口相同,再展示。下面是配置文件以及使用反射实现的工厂

package com.cliong.aoptest.aop;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.util.Properties;

/**
 * @author lc
 * @date 2020-12-17 19:40
 */
public class PropertiesFactory {
    static Fruit getInstance() {
        Properties properties = new Properties();
        InputStream inputStream = PropertiesFactory.class.getResourceAsStream("/factory-config.properties");
        try {
            properties.load(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        Fruit fruit = null;
        try {
            fruit = (Fruit) Class.forName(properties.getProperty("ImplClass")).getConstructor().newInstance();
        } catch (ClassNotFoundException | NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
        }
        return fruit;
    }

    public static void main(String[] args) {
        System.out.println(getInstance());
    }
}

配置文件如下

ImplClass=com.cliong.aoptest.aop.Banana

这样就可以实现使用配置文件来添加实例了。

重要:让我们再扩展的想一想,这里面配置了很多的类,然后为了区分开来都给一个唯一的东西,也就是ID,让ID与实例对应起来,使用时通过id来获取对应的实例。然后又有人说了,这样定义对象里面的内容,出来的都是原来设置好的。为了解决这样的问题,我们可以再增加一些配置,用来设置对象实例里面的一些属性,然后还可以设置成是不是单例的,这样就很方便了。但是过多的配置使得properties文件过于冗杂,不宜配置。这时我们会想到XML的规范性,利用一些标签代表一些属性配置,这样就增加了可读性,还有这些配置最好封装成一个对象,那样使用起来方便了,这个类就叫BeanDefinition吧。

你看这样是不是就很像Spring的核心容器了。

简单工厂有以下优点

  • 帮助封装

    简单工厂虽然很简单,但是非常友好地帮助我们实现了组件的封装,然后让组件外部能真正面向接口编程

  • 解耦

    通过简单工厂,实现了客户端和具体实现类的解耦。

    如同上面的例子,客户端根本就不知道具体是由谁来实现,也不知道具体是如何实现的,客户端只是通过工厂获取它需要的接口对象。

简单工厂有以下缺点。

  • 可能增加客户端的复杂度
    如果通过客户端的参数来选择具体的实现类,那么就必须让客户端能理解各个参数所代表的具体功能和含义,这样会增加客户端使用的难度,也部分暴露了内部实现,这种情况可以选用可配置的方式来实现。
  • 不方便扩展子工厂
    私有化简单工厂的构造方法,使用静态方法来创建接口,也就不能通过写简单工厂类的子类来改变创建接口的方法的行为了。不过,通常情况下是不需要为简单工厂创建子类的。
posted @ 2020-12-17 20:07  小鸡小鸡快点跑  阅读(57)  评论(0)    收藏  举报