Java中的开闭原则

    科技2025-04-20  16

    文章目录

    1.什么是开闭原则?2.什么是面向接口编程?3.面向接口编程的好处:4.代码实现案例:

    1.什么是开闭原则?

    即对修改关闭对扩展开放,允许拓展系统功能而不允许修改功能的实现方式。

    而在实际开发中,开闭原则就意味着需要面向接口编程,也就是面向接口编程才能更好的实现开闭原则。

    2.什么是面向接口编程?

    可能直接的理解是使用接口,然后创建实现类,但这好像并不完整。

    完整的面向接口编程应该是基于MVC分层来看的,MVC分层之后,每一层在调用的时候,只创建接口,具体的实现类由配置文件决定。

    接口限定了每个方法的功能、参数和返回值,这样的好处在于如果需求改变的时候,只需要修改配置文件和实现类即可。

    而如果使用传统的方式去编写代码,无论那一层出现问题,你都需要解决上一层的交互和下一层的交互,而且需要整个去测试,避免出现问题,而面向接口开发则不会有这个问题。

    3.面向接口编程的好处:

    1.易于拓展:在拓展功能的时候,只需要更换添加接口中的方法更改实现类即可实现拓展,而其他层也只需要根据给出的方法来稍加改动。

    2.隐藏实现:MVC分层之后,我们调用方法的时候,只需要调用接口中的方法即可,具体的实现由配置文件和其他具体的实现类来决定。

    4.代码实现案例:

    在这个案例中会用到反射、properties集合等,如果对于反射不了解的话,可以看一下我写的Java学习笔记之反射机制

    首先是定义好的几个接口:

    //数据访问层接口 public interface UserDao { int login(String username, String password); } //业务层接口 public interface UserService { int login(String username, String password); }

    然后是数据访问层的具体实现类:

    //模拟MySQL实现用户登录 public class MySqlImpl implements UserDao { @Override public int login(String username, String password) { System.out.println("mysql 实现用户登录"); return 0; } } //模拟Oracle实现用户登录 public class OracleImpl implements UserDao { @Override public int login(String username, String password) { System.out.println("oracle 实现用户登录"); return 0; } }

    然后是普通的业务层:

    public class UserServiceImpl implements UserService { //根据需求创建具体的类,这样做并不好 //因为一般需要变更实现类,就需要大量修改代码 private MySqlImpl user= new MySqlImpl(); @Override public int login(String username, String password) { return user.login(username, password); } } public class UserServiceImpl implements UserService { //初步改良后,如果修改了数据库,就只需要修改后面的实现类即可 //这样做依旧有问题,那就是直接把代码写死了 //修改实现类之后仍然需要修改这里的代码 private UserDao userDao = new MySqlImpl(); @Override public int login(String username, String password) { return userDao.login(username, password); } }

    如果想要更加便捷,那么就需要通过配置文件和反射来实现了,下面是配置文件:

    # 配置接口的映射信息 # 配置UserDao接口的实现类 UserDao=com.ps.dao.impl.OracleImpl # 配置业务层UserService的实现类 UserService=com.ps.service.impl.UserServiceImpl

    接下来就是创建工具类,通过工具类来创建具体的实现类对象

    //用来创建数据访问层的具体实现类 public class DaoUtil { //通过反射来创建对应的类对象,所以需要使用泛型来获得 public static <T> T newInstance(Class<T> getClass) { try { //1.判断传入的是否是接口类型 //如果不是接口类型就无法读取到配置文件中的信息 if (getClass.isInterface()) { //2.获得接口的接口名 String name = getClass.getSimpleName(); //3.从配置文件中获取实现类的类全名字符串 String className = ResourceBundle.getBundle("Dao").getString(name); //4.利用反射获取这个类的class对象 Class result = Class.forName(className); //5.利用class对象创建类 T resultClass = (T) result.newInstance(); //6.返回得到的类型 return resultClass; } } catch (ClassNotFoundException e) { e.printStackTrace(); } return null; } }

    然后修改各个层的创建方式:

    业务层:

    public class UserServiceImpl implements UserService { //这样编写的话,只需要更改配置文件中的信息,即可 private UserDao userDao = DaoUtil.newInstance(UserDao.class); @Override public int login(String username, String password) { return userDao.login(username, password); } }

    表现层:

    public class UserServlet extends HttpServlet { //这样编写的话,只需要更改配置文件中的信息,即可 private UserService userService = DaoUtil.newInstance(UserService.class); @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //1.从页面获取数据 String username = request.getParameter("username"); String password = request.getParameter("password"); //2.调用业务层的方法 int login = userService.login(username, password); //3.把结果返回给页面 response.getWriter().print(login); } }
    Processed: 0.011, SQL: 8