zoukankan      html  css  js  c++  java
  • 多态和简单对象工厂

      Java 的反射技术和多态特性是框架开发、组件解耦的核心,在这方面,Spring 的 IOC 和 DI 为我们提供了一个极好的学习范例,Spring 的 IOC 使用反射技术创建、管理对象,DI 使用多态技术为组件注入依赖对象。

      在没有学习 Spring 之前,简单的解决方案是使用一个 .properties 文件保存程序中使用的接口、实现类类型键值信息,然后在程序中使用一个全局 Properties 对象保存这些信息,并且使用反射技术把这些实现类初始化、提供一个静态的方法获取指定接口的实现类对象,在组件中就可以使用依赖对象的键获取需要的对象。

      这样的方案带来的好处就是:当我们需要修改某个组件的实现方式时,比如把之前 JDBC 的 DAO 实现改为 Hibernate 实现,只要把这些新的实现类放到 classpath 下,把 .properties 文件对应接口的实现类类型改成新的 Hibernate 实现类,而不需要修改依赖组件的代码。

    1、接口和抽象类

      共同点:

      (1)二者都不能创建对象;

      (2)抽象方法要被实现,不能是静态的,也不能是私有的;

      (3)一个类如果没有实现父类或接口的全部抽象方法,那么该类只能为抽象类

      区别:

      (1)接口可以继承接口,而且可以多继承,但是不能实现;类只能继承一个父类或抽象类,但可以实现多个接口;

      (2)抽象类可以有构造方法,接口不能有构造方法;

      (3)接口都是抽象方法;抽象类可以没有抽象方法,而且一个类如果有抽象方法,那么这个类就必须是抽象类;

      (4)接口只能定义公共静态的常量;抽象类中可以定义普通变量;

      (5)接口更适合做子系统、组件、模块的技术、功能规范;抽象类更适合做通用业务逻辑的抽象和封装。比如:DAO、Service 层的核心功能就需要使用接口来规范;而DAO层实现类都具有的一些通用逻辑就可以放在一个抽象类中,然后让具体的DAO实现类来继承这个抽象类。

    2、方法的重写和重载

      方法的重写 Override 和重载 Overload 都是 Java 多态的不同表现。重写 Override 是父类与子类之间多态性的一种表现,重载 Overload 是一个类中多态性的一种表现。

      重写:也叫做覆盖。子类中的方法与父类中的某一方法具有相同的方法名、返回值类型和参数列表,则该方法将覆盖父类方法。有几点需要注意:

      (1)子类方法不能抛出比父类方法更多或“更大”的异常;

      (2)子类方法的访问权限级别不能比父类方法更严格;

      (3)一定要有相同的返回值类型;

      (4)参数列表需要相同,如果不同,那么这个方法相当于重载,而不是重写

      重载:一个类中定义了多个同名的方法,它们的参数个数或参数类型不同,这种情况就是方法重载。但是和返回值的类型无关。

    3、示例代码概述

      目录结构如下:

      

    4、DAO接口和默认实现

       UserDao接口

     1 public interface UserDao {
     2 
     3     public void add();
     4 
     5     public void del();
     6 
     7     public void update();
     8 
     9     public void get();
    10 }

       UserDaoImpl 实现类

     1 public class UserDaoImpl implements UserDao {
     2 
     3     public void add() {
     4         System.out.println("使用的是demo.dao.impl.UserDaoImpl的添加方法");
     5     }
     6 
     7     public void del() {
     8 
     9         System.out.println("使用的是demo.dao.impl.UserDaoImpl的删除方法");
    10     }
    11 
    12     public void update() {
    13 
    14         System.out.println("使用的是demo.dao.impl.UserDaoImpl的更新方法");
    15     }
    16 
    17     public void get() {
    18 
    19         System.out.println("使用的是demo.dao.impl.UserDaoImpl的获取方法");
    20     }
    21 }

    5、Service接口和默认实现

      UserService 接口

     1 public interface UserService {
     2 
     3     public void addUser();
     4 
     5     public void delUser();
     6 
     7     public void updateUser();
     8 
     9     public void getUser();
    10 }

      UserServiceImpl 实现类,注意在这里需要使用对象工厂注入依赖的 DAO 对象

     1 public class UserServiceImpl implements UserService {
     2 
     3     private UserDao userDao;
     4 
     5     public UserServiceImpl() {
     6         super();
     7         this.userDao = (UserDao) ObjectFactory.getObject("userDao");
     8     }
     9 
    10     public void addUser() {
    11         this.userDao.add();
    12         System.out.println("使用的是demo.service.impl.UserServiceImpl的addUser方法");
    13     }
    14 
    15     public void delUser() {
    16         this.userDao.del();
    17         System.out.println("使用的是demo.service.impl.UserServiceImpl的delUser方法");
    18     }
    19 
    20     public void updateUser() {
    21         this.userDao.update();
    22         System.out
    23                 .println("使用的是demo.service.impl.UserServiceImpl的updateUser方法");
    24     }
    25 
    26     public void getUser() {
    27         this.userDao.get();
    28         System.out.println("使用的是demo.service.impl.UserServiceImpl的getUser方法");
    29     }
    30 }

    6、ObjectFactory 类和 objects.properties

      首先,看一下 objects.properties 配置文件,主要配置程序使用的接口实现类类型信息

      

    1 userDao=demo.dao.impl.UserDaoImpl
    2 userService=demo.service.impl.UserServiceImpl

      我们需要写个 ObjectFactory 类读取配置并实例化对象,然后保存到全局“工厂”

     1 public final class ObjectFactory {
     2     
     3     /**
     4      * 保存接口的键(通常使用接口的简单类名首字母小写)和实现类对象信息<br/>
     5      * 
     6      * 使用者可以调用getObject方法传入配置文件中key获取对应实现类对象<br/>
     7      */
     8     private static Map<String, Object> objectMap = new HashMap<String, Object>();
     9     
    10     /**
    11      * 用于加载配置文件
    12      */
    13     private static Properties prop = new Properties();
    14     
    15     static {
    16         try {
    17             // 读取配置文件
    18             prop.load(ObjectFactory.class.getClassLoader().getResourceAsStream("objects.properties"));
    19             // 迭代properties,对实现类逐一进行实例化
    20             // 然后把实现类对象保存到objectMap中
    21             for(Object k : prop.keySet()) {
    22                 String key = k.toString();
    23                 // 获取值,即实现类的权限定名
    24                 String className = prop.get(key).toString();
    25                 // 加载类并实例化
    26                 Class<?> cls = Class.forName(className);
    27                 Object obj = cls.newInstance();
    28                 // 把实现类对象保存到objectMap
    29                 objectMap.put(key, obj);
    30             }
    31         } catch (IOException e) {
    32             e.printStackTrace();
    33             throw new RuntimeException("加载全局接口实现类配置文件失败", e);
    34         } catch (ClassNotFoundException e) {
    35             e.printStackTrace();
    36             throw new RuntimeException("有实现类未找到", e);
    37         } catch (InstantiationException e) {
    38             e.printStackTrace();
    39             throw new RuntimeException("类实例化出错", e);
    40         } catch (IllegalAccessException e) {
    41             e.printStackTrace();
    42             throw new RuntimeException("类访问出错", e);
    43         }
    44     }
    45     
    46     /**
    47      * 根据指定接口的键(通常使用接口的简单类名首字母小写)获取对应配置的实现类对象
    48      */
    49     public static Object getObject(String key) {
    50         return objectMap.get(key);
    51     }
    52 }
    View Code

    7、Servlet 和 JSP

       DecoupleServlet 类,需要使用对象工厂获取 Service 对象

     1 public class DecoupleServlet extends HttpServlet {
     2 
     3     private static final long serialVersionUID = 1L;
     4 
     5     public DecoupleServlet() {
     6         super();
     7     }
     8 
     9     protected void doGet(HttpServletRequest request,
    10             HttpServletResponse response) throws ServletException, IOException {
    11         doPost(request, response);
    12     }
    13 
    14     protected void doPost(HttpServletRequest request,
    15             HttpServletResponse response) throws ServletException, IOException {
    16 
    17         request.setCharacterEncoding("UTF-8");
    18         response.setContentType("text/html; charset=utf-8");
    19 
    20         UserService userService = (UserService) ObjectFactory
    21                 .getObject("userService");
    22 
    23         userService.addUser();
    24 
    25         request.setAttribute("service", userService.getClass().getName());
    26 
    27         request.getRequestDispatcher("demo.jsp").forward(request, response);
    28     }
    29 }

      index.jsp 和 demo.jsp 省略。

      启动项目后访问 http://localhost:8080/demo/

      

      点击页面链接

      

      从页面和控制台输出,可以看出程序确实使用了默认的 DAO 和 Service

    8、修改 DAO 实现类配置

       首先,编写一个新的 DAO 实现类 UserHibernateDao

     1 public class UserHibernateDao implements UserDao {
     2 
     3     public void add() {
     4         System.out.println("使用的是demo.dao.hibernate.UserHibernateDao的添加方法");
     5     }
     6 
     7     public void del() {
     8         System.out.println("使用的是demo.dao.hibernate.UserHibernateDao的删除方法");
     9     }
    10 
    11     public void update() {
    12         System.out.println("使用的是demo.dao.hibernate.UserHibernateDao的更新方法");
    13     }
    14 
    15     public void get() {
    16         System.out.println("使用的是demo.dao.hibernate.UserHibernateDao的获取方法");
    17     }
    18 }

      修改配置

    1 # userDao=demo.dao.impl.UserDaoImpl
    2 userDao=demo.dao.hibernate.UserHibernateDao
    3 userService=demo.service.impl.UserServiceImpl

      重启项目,重新访问

     

      可以看到控制台输出,已经成功地使用了新的 DAO 实现类。

  • 相关阅读:
    redis深度理解底层锁原理
    深度完整的了解MySQL锁
    今天的文章很不一般
    利用h5来进行定位当前位置
    workerman(环境+初识)
    Nginx(防止压力测试的恶意攻击)
    Java Web框架——自己动手实现一个简化版的Spring IOC框架
    设计模式——策略模式
    数据库——深入理解MySQL事务
    缓存——Redis和Memcache的对比
  • 原文地址:https://www.cnblogs.com/xugf/p/8480575.html
Copyright © 2011-2022 走看看