码迷,mamicode.com
首页 > 其他好文 > 详细

工厂模式

时间:2020-05-24 11:30:19      阅读:54      评论:0      收藏:0      [点我收藏+]

标签:turn   读取   service   构造   工具类   instance   面向接口   iat   pre   

什么是工厂设计模式

1. 概念:通过工厂类创建对象
2. 好处:解耦合
3. 耦合:代码之间产生强关联,修改一方会影响到另一方

解耦的本质在于隔离变化

耦合与解耦合本质在于对变化的处理。

通常如果将接口的实现类硬编码在程序中,就会使得变化散落在程序各处,使得修改会产生连锁反应。

但代码不能完全解耦,如果代码间完全没有关联那程序也就无法正常运行。

所以,解耦的本质在于:隔离变化。

分析这段代码:

UserService userService = new UserServiceImpl();

首先在等号的左侧,我们通过面向接口编程的方式将变化隔离到右侧的实现类部分,但是右侧仍然存在耦合关系,如何将右侧的new UserServiceImpl()也进行解耦呢?

对象的创建方式

讨论对象实现类的解耦之前,首先要了解对象的创建方式。

对象创建方式有两种:

  1. 直接调用构造方法创建对象,即new的方式。
UserService userService = new UserServiceImpl();
  1. 通过反射的形式创建对象。
Class clazz = Class.forName("com.peter.UserServiceImpl");
UserService userService = (UserService)clazz.newInstance();

显然,如果通过第一种方式直接构造对象需要首先导入该实现类,其次要通过new语句硬编码类对象的创建,那么必然带来耦合。而通过反射的形式创建对象,则可以将类的变化转变为一个字符串,而对于字符串而言又可以将其隔离到配置文件进行读取,这样我们的代码就不需要跟随实现类的变化而做很大的调整。

我们创建一种通过反射的形式创建对象的工具类,通过它来完成对象的创建,这种模式叫做工厂模式,这个工具类叫做反射工厂。

简单工厂和通用工厂

知道了工厂的基本原理,大体上我们可以进行相应的实现。比如我们要创建一个方法用于实现UserService对象,那么可以这样做:

  1. 定义接口
public interface UserService {
  void getUser();
}
  1. 定义实现类
public class UserServiceImpl implements UserService {
  public void getUser() {
    System.out.println("get a user");
  }
}
  1. 定义配置文件
# applicationContext.properties
userService = com.peter.UserServiceImpl
  1. 定义工厂
public class BeanFactory {
  private static Properties env = new Properties();
  static {
    try {
      InputStream config = BeanFactory.class.getResourceAsStream("/applicationContext.properties");
      env.load(config);
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
	
  public static UserService getUserService() {
    UserService userService = null;
    try {
      Class clazz = Class.forName(env.getProperty("userService"));
      userService = (UserService)clazz.newInstance();
    } catch (ClassNotFoundException e) {
      e.printStackTrace();
    } catch (IllegalAccessException e) {
      e.printStackTrace();
    } catch (InstantiationException e) {
      e.printStackTrace();
    }
    return userService;
  }
  1. 调用工厂
public class Main {
  public static void main(String[] args) {
      // 简单工厂
      UserService userService = BeanFactory.getUserService();
      userService.getUser();
  }
}

在第四步定义工厂时,我们定义了getUserService方法用于获取UserService接口类型的对象,这种针对某一类型单独定义方法的工厂叫做简单工厂。但是,在简单工厂中,很多代码实际上都是样板代码,如果我们需要添加一个类型则需要重复编写这些代码,于是我们想到要进一步抽象使其更加通用。

  public static Object getBean(String key) {
    Object ret = null;
    try {
      Class clazz = Class.forName(env.getProperty(key));
      ret = clazz.newInstance();
    } catch (ClassNotFoundException e) {
      e.printStackTrace();
    } catch (InstantiationException e) {
      e.printStackTrace();
    } catch (IllegalAccessException e) {
      e.printStackTrace();
    }
    return ret;
  }

我们将原先与UserService相关的部分抽象为Object和入参key,这样我们就实现了一个通用的类对象创建方式,实现了这种方法的工厂叫做通用工厂

我们看如何调用通用工厂:

public class Main {
  public static void main(String[] args) {
      // 通用工厂
      UserService userService = (UserService)BeanFactory.getBean("userService");
      userService.getUser();
  }
}

到此为止,我们使用通用工厂+配置文件的方式将变化隔离到了配置文件,保证了代码的解耦合。

总结

代码解耦由三个重要的部分组成:接口、工厂、配置文件。

通过接口和工厂实现代码逻辑的组装,通过配置文件实现了变化的隔离和实现类的注入。我们可能觉得这和Spring的设计思想是一致的,其实Spring中IOC容器的本质就是这么一个通用工厂,名字叫做ApplicationContext,而相应的配置文件叫做applicationContext.xml。

源代码: https://github.com/PeterWangYong/blog-code/tree/master/factory

工厂模式

标签:turn   读取   service   构造   工具类   instance   面向接口   iat   pre   

原文地址:https://www.cnblogs.com/Peter2014/p/12950011.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!