通过多态,反射,配置文件,工厂来解耦

案例学生管理系统,获取所有学生的功能
1.控制层

@WebServlet("/GetAllStuServlet")
public class GetAllStuServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("UTF-8");//解决post中文乱码问题
        resp.setContentType("text/html;charset=UTF-8");//解决响应到前台中文乱码的问题

        StudentService ss=new StudentService();

        ArrayList<Student> arrayList= null;
        try {
            arrayList = ss.getAllStu();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        req.setAttribute("stulist",arrayList);
       
        req.getRequestDispatcher("/stulist.jsp").forward(req,resp);
    }
}

2.业务层


public class StudentService {
    public ArrayList<Student> getAllStu() throws SQLException {
    	StudentDao std=new StudentDao();
        ArrayList<Student> arrayList= std.getAllStu();
        return  arrayList;
    }
}

3.dao层

public class StudentDao {
public ArrayList<Student> getAllStu() throws SQLException {
        ArrayList<Student> arrayList = new ArrayList<>();
        Connection con = GetCon.getCon();
        if (con!=null){
            Statement statement = con.createStatement();
            String sql="SELECT *  FROM  student ";
            ResultSet resultSet = statement.executeQuery(sql);
            while (resultSet.next()){
                String id = resultSet.getString("id");
                String name = resultSet.getString("stuname");
                String gender = resultSet.getString("gender");
                String age = resultSet.getString("age");
                arrayList.add(new Student(name,Integer.parseInt(age),gender));
            }
            con.close();
        }
        return arrayList;
    }
   }

开始BB
上面的dao层是用的jdbc实现获取连接,如果要求采用c3p0连接池技术获取连接,按照开闭原则,我们得重写这个StudentDao,当然过两天又可能又使用Druid来获取连接的需求,那么按照开闭原则我们又得重新写一个StudentDao。几个StudentDao不能删除就导致业务层造对象得一直改

StudentDao111 std=new StudentDao111();
StudentDaoJdbc std=new StudentDaoJdbc();
StudentDaoDruid std=new StudentDaoDruid();

那么我们就可以开展解耦的第一个阶段了,使用多态对上面的三个操作进行解耦,为了解决把左边写死的问题,我们可以为上面三个类抽取一个接口。

StudentDao std=new StudentDaoImpl111();
StudentDao std=new new StudentDaoJdbcImpl();
StudentDao std=new StudentDaoDruidImpl();

我们又发现一个问题,左边的耦合解开了,右边的还没有解开,我们得想一个方法来动态的创造右边的实例,接下来就到了解耦的第二阶段。我们可以在src下创建一个配置文件,里面写上Dao实现类的全类名,然后通过加载配置文件动态获取全类名,有了全类名就可以通过反射来造对象了。

studentDao=com.it.mark.dao.StudentDaoImpl
 InputStream rs =   StudentServiceImpl.class.getClassLoader().getResourceAsStream("bean.properties");
 Properties  properties =new Properties();
 StudentDao std=(StudentDao) Class.forName(properties.getProperty("studentDao")).newInstance()

此时右边的耦合也解开了,我们觉得这个方法很赞,想把这样的方法应用到业务层,可是发现一个问题,业务层也要写上读配置文件,加载配置文件,反射造对象的代码。所以我们可以对上面的代码进行抽取。这就到了解耦升级阶段–使用工厂类来动态造对象

public class MyBeanFactory {
    public static Object getBean(String id){
        try {
            InputStream ras = MyBeanFactory.class.getClassLoader().getResourceAsStream("bean.properties");
            Properties properties=new Properties();
            properties.load(ras);
            return Class.forName(properties.getProperty(id)).newInstance();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }
    private MyBeanFactory() {
    }
}

我们对外暴露一个String类型的id,通过它就可以获取加载到集合中的类的全路径,进而造对象。
至此解耦完毕。

上一篇:7 Spring控制事务的开发


下一篇:MyBatis——封装MyBatis的输出结果(resultType、resultMap)、使用like进行模糊查询的两种方式