Java中的开闭原则

文章目录

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);
    }
}
    原文作者:曲水流觞笑醉尘
    原文地址: https://blog.csdn.net/qq_42525761/article/details/108959107
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞