简单工厂模式

简单工厂模式

简单工厂模式是工厂方法的简化版,又称之为静态工厂方法
下面给出简单工厂方法的类结构

这里写图片描述

有了类图结构就可以根据类图写出相应的代码了.
首先是产品类,我们将同一类产品抽象为一个接口,表示这是一类产品,例如汽车类,定义一个汽车Car接口

Car汽车接口

/**
 *@DESCRIPTION 这是一个汽车接口
 *@AUTHOR SongHongWei
 *@TIME 2018/8/11-23:40
 *@PACKAGE_NAME test.factory.simple
 **/
public interface Car
{
    public void description();
}

对于Car汽车接口有很多实现类,例如宝马,奥迪,奔驰等等,那么下面就要定义具体的产品了,我们定义两个汽车产品,分别是BMW和Audi

产品实现类

BMW

 /*
 *@DESCRIPTION 宝马汽车
 *@AUTHOR SongHongWei
 *@TIME 2018/8/11-23:40
 *@PACKAGE_NAME test.factory.simple
 **/
public class BMW implements Car
{
    @Override
    public void description()
    {
        System.out.println("This is BMW");
    }
}

Audi

 /*                  
 *@DESCRIPTION 奥迪汽车
 *@AUTHOR SongHongWei
 *@TIME 2018/8/11-23:40
 *@PACKAGE_NAME test.factory.simple
 **/
public class Audi implements Car
{
    @Override
    public void description()
    {
        System.out.println("This is Audi");
    }
}

现在有了产品,我们就需要用来生产产品的工厂,所以需要建立一个用于生产汽车的汽车工厂

汽车工厂

    /**
     *@DESCRIPTION 根据不同的产品名称生产不同的产品,这里的返回值用Object接收,后面优化时用反射
     *@AUTHOR SongHongWei
     *@TIME 2018/8/11-23:31
     *@CLASS_NAME SimpleFactory
     **/
    public Object getProduct(String productName)
    {
        if ("BMW".equals(productName))
        {
            return new BMW();
        }
        else if ("Audi".equals(productName))
        {
            return new Audi();
        }
        return null;
    }

现在有了汽车工厂又有了产品,作为客户我们就可以命令工厂去生产指定的产品,假如我现在想要有一辆宝马,那我就跟工厂说,给我生产一辆宝马出来,代码实现方式就是

 /*
 *@DESCRIPTION 客户调用
 *@AUTHOR SongHongWei
 *@TIME 2018/8/11-23:33
 *@PACKAGE_NAME test.factory.simple
 **/
public class Client
{
    public static void main(String[] args)
    {
        SimpleFactory simpleFactory = new SimpleFactory();
        Car car = (Car)simpleFactory.getProductByReflect("BMW");
        car.description();
    }
}

输出结果为:

This is BMW
Process finished with exit code 0

其实作为上面的工厂方法可以利用java的反射去优化,这样就不用因为新增了汽车产品而一直else if下去了

修改后的工厂实现方法

   /**
     *@DESCRIPTION 这里引入了PropertiesUtil工具类
     *@AUTHOR SongHongWei
     *@TIME   2018/8/12-0:18
     *@CLASS_NAME SimpleFactory
    **/ 
 public static Object getProductByReflect(String productName)
    {
        String className = PropertiesUtil.getPropertyValue(productName);
        try
        {
          return  Class.forName(className).newInstance();
        }
        catch (InstantiationException e)
        {
            e.printStackTrace();
        }
        catch (IllegalAccessException e)
        {
            e.printStackTrace();
        }
        catch (ClassNotFoundException e)
        {
            e.printStackTrace();
        }
        return null;
    }

上述代码中引入了一个PropertiesUtil工具类,这个工具类是为了读取properties文件里面的内容的,为什么要建立.properties文件呢,因为java里面的反射机制是通过加载类的全路径是得到类的字节码的,作为调用者来说,根本就不知道类的全路径是什么,如果知道了,那根本就用不了工厂方法,直接去new出来就行了,对于用户来说,用户只知道他想要什么产品,而不去关心产品是怎么是实现或生成的,例如,我想要辆BMW,我不需要知道BMW的实现类是谁,我只要告诉工厂我要BMW就可以了,那么工厂怎么根据BMW去获取对应的类的全路径呢,这时就需要用到.properties文件了,我们可以事先在.properties文件里定义好BMW对应的类的全路径,就行Spring里bean的配置文件一样,定义一个id 后面跟着class的全路径,我们这里定义一个key后面跟着类的全路径,properties的内容如下所示:

bean.properties

BMW=test.factory.simple.BMW
Audi=test.factory.simple.Audi

PropertiesUtil 工具类的实现

public class PropertiesUtil
{
    /**
     *@DESCRIPTION 根据key值获取properties文件的value
     *@AUTHOR SongHongWei
     *@TIME 2018/8/12-0:09
     *@CLASS_NAME PropertiesUtil
     **/
    public static String getPropertyValue(String key)
    {
        String value = null;
        try
        {
            InputStream in = Properties.class.getResourceAsStream("/test/factory/simple/bean.properties");
            Properties p = new Properties();
            p.load(in);
            value = p.getProperty(key);
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
        return value;
    }

}

客户端的修改

/**
 *@DESCRIPTION ${END}
 *@AUTHOR SongHongWei
 *@TIME 2018/8/11-23:33
 *@PACKAGE_NAME test.factory.simple
 **/
public class Client
{
    public static void main(String[] args)
    {
            Car car = (Car)SimpleFactory.getProductByReflect("BMW");
            car.description();
    }
}

输出结果:

This is BMW

Process finished with exit code 0

总结

优点:简单工厂模式能够根据外界给定的信息,决定究竟应该创建哪个具体类的对象。明确区分了各自的职责和权力,有利于整个软件体系结构的优化。用户在使用时可以直接根据工厂类去创建所需的实例,而无需了解这些对象是如何创建以及如何组织的。有利于整个软件体系结构的优化。

缺点:由于工厂类集中了所有实例的创建逻辑,这就直接导致一旦这个工厂出了问题,所有的客户端都会受到牵连;而且由于简单工厂模式的产品室基于一个共同的抽象类或者接口,这样一来,一旦产品的种类增加的时候,即有不同的产品接口或者抽象类的时候,工厂类就需要判断何时创建何种种类的产品,这就和创建何种种类产品的产品相互混淆在了一起,违背了单一职责和“开放封闭原则”,因为当我们新增加一个产品的时候必须修改工厂类,相应的工厂类就需要重新编译一遍。

JDK中使用案例

在jdk1.7中,线程池Executors就使用了静态工厂方法,有兴趣的可以去看一下源码

Executors 的构造方法

构造方法被私有化了,也就是说不能new出来

     /**
      * Cannot instantiate. 
      */
    private Executors() {}

Executors 提供的一些静态工厂方法

  /**
     * Creates a single-threaded executor that can schedule commands
     * to run after a given delay, or to execute periodically.
     * (Note however that if this single
     * thread terminates due to a failure during execution prior to
     * shutdown, a new one will take its place if needed to execute
     * subsequent tasks.)  Tasks are guaranteed to execute
     * sequentially, and no more than one task will be active at any
     * given time. Unlike the otherwise equivalent
     * <tt>newScheduledThreadPool(1)</tt> the returned executor is
     * guaranteed not to be reconfigurable to use additional threads.
     * @return the newly created scheduled executor
     */
 public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }

  /**
     * Creates a single-threaded executor that can schedule commands
     * to run after a given delay, or to execute periodically.
     * (Note however that if this single
     * thread terminates due to a failure during execution prior to
     * shutdown, a new one will take its place if needed to execute
     * subsequent tasks.)  Tasks are guaranteed to execute
     * sequentially, and no more than one task will be active at any
     * given time. Unlike the otherwise equivalent
     * <tt>newScheduledThreadPool(1)</tt> the returned executor is
     * guaranteed not to be reconfigurable to use additional threads.
     * @return the newly created scheduled executor
     */
  public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
        return new DelegatedScheduledExecutorService
            (new ScheduledThreadPoolExecutor(1));
    }
阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页