• 工厂模式


    什么是工厂设计模式

    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

  • 相关阅读:
    最热CPLDFPGA论坛
    DSP Builder开发环境安装
    math.h数学函数库
    (转)Fast Input/Output Registers约束
    用EXCEL去掉最高最低数,网上看到,觉得不错
    GMS6.5.3有0DAY的下载了
    [转]为ArcGIS制作符号
    Total Commander 7.5Beta1的便携版
    关于CAD的一个小发现
    可恶的AP PDF password recovery
  • 原文地址:https://www.cnblogs.com/Peter2014/p/12950011.html
Copyright © 2020-2023  润新知