Let’s take a life example. When we are happy, we may seek pleasure. Before learning about design patterns, you might say something like:

After studying design patterns, you might say something like:

How do you feel about the difference before and after?

Back in the code, let’s think about what problems can design patterns solve?

Write elegant code

Let’s start with a piece of code THAT I wrote many years ago.


public void setExammingForm(ExammingForm curForm,String parameters)throws BaseException {... JSONObject jsonObj =new JSONObject(parameters);
      // Test primary key
      if(jsonObj.getString("examinationPaper_id")! =null&& (! jsonObj.getString ("examinationPaper_id").equals("")))
         curForm.setExaminationPaper_id(jsonObj.getLong("examinationPaper_id"));
      // The remaining time
      if(jsonObj.getString("leavTime") != null&& (! jsonObj.getString("leavTime").equals("")))
         curForm.setLeavTime(jsonObj.getInt("leavTime"));
      // Unit primary key
      if(jsonObj.getString("organization_id")! =null&& (! jsonObj.getString ("organization_id").equals("")))
         curForm.setOrganization_id(jsonObj.getLong("organization_id"));
      // Test primary key
      if(jsonObj.getString("id")! =null&& (! jsonObj.getString("id").equals("")))
         curForm.setId(jsonObj.getLong("id"));
      // The main key of the examination room
      if(jsonObj.getString("examroom_id")! =null&& (! jsonObj.getString ("examroom_id").equals("")))
         curForm.setExamroom_id(jsonObj.getLong("examroom_id"));
      // Use the primary key
      if(jsonObj.getString("user_id")! =null&& (! jsonObj.getString("user_id").equals("")))
         curForm.setUser_id(jsonObj.getLong("user_id"));
      // Professional code
      if(jsonObj.getString("specialtyCode")! =null&& (! jsonObj.getString ("specialtyCode").equals("")))
         curForm.setSpecialtyCode(jsonObj.getLong("specialtyCode"));
      // Apply for the position
      if(jsonObj.getString("postionCode")! =null&& (! jsonObj.getString ("postionCode").equals("")))
         curForm.setPostionCode(jsonObj.getLong("postionCode"));
      // Register a level
      if(jsonObj.getString("gradeCode")! =null&& (! jsonObj.getString ("gradeCode").equals("")))
         curForm.setGradeCode(jsonObj.getLong("gradeCode"));
      // Test start time
      curForm.setExamStartTime(jsonObj.getString("examStartTime"));
      // Test end time
      curForm.setExamEndTime(jsonObj.getString("examEndTime")); . }Copy the code

The optimized code looks like this.


public class ExammingFormVo extends ExammingForm{

   private String examinationPaperId;	// Test primary key
   private String leavTime;				// The remaining time
   private String organizationId;		// Unit primary key
   private String id;					// Test primary key
   private String examRoomId;			// The main key of the examination room
   private String userId;				// Use the primary key
   private String specialtyCode;		// Professional code
   private String postionCode;			// Apply for the position
   private String gradeCode;			// Register a level
   private String examStartTime;		// Test start time
   private String examEndTime;			// Test end time. }public void setExammingForm(ExammingForm form,String parameters)throws BaseException {
   try {
      JSONObject json = new JSONObject(parameters);
      ExammingFormVo  vo = JSONObject.parseObject(json,ExammingFormVo.class);

      form = vo;

   }catch(Exception e){ e.printStackTrace(); }}Copy the code

Refactor the project better

Although the code we write meets the requirements, it is often not conducive to the development and maintenance of the project. The JDBC code below is an example.

public void save(Student stu){
    String sql = "INSERT INTO t_student(name,age) VALUES(? ,?) ";
    Connection conn = null;
    Statement st = null;
    try{
        //1. Load the registered driver
        Class.forName("com.mysql.jdbc.Driver");
        //2. Obtain the database connection
        conn=DriverManager.getConnection("jdbc:mysql:///jdbc_demo"."root"."root");
        //3. Create statement objects
        PreparedStatement ps=conn.prepareStatement(sql);
        ps.setObject(1,stu.getName());
        ps.setObject(2,stu.getAge());
        //4. Execute the SQL statement
        ps.executeUpdate();
        //5. Release resources
    }catch(Exception e){
        e.printStackTrace();
    }finally{
        try{
            if(st ! =null)
                st.close();
        }catch(SQLException e){
            e.printStackTrace();
        }finally{
            try{
                if(conn ! =null)
                    conn.close();
            }catch(SQLException e){ e.printStackTrace(); }}}}// Delete student information
public void delete(Long id){
    String sql = "DELETE FROM t_student WHERE id=?";
    Connection conn = null;
    Statement st = null;
    try{
        //1. Load the registered driver
        Class.forName("com.mysql.jdbc.Driver");
        //2. Obtain the database connection
        conn=DriverManager.getConnection("jdbc:mysql:///jdbc_demo"."root"."root");
        //3. Create statement objects
        PreparedStatement ps = conn.prepareStatement(sql);
        ps.setObject(1,id);
        //4. Execute the SQL statement
        ps.executeUpdate();
        //5. Release resources
    }catch(Exception e){
        e.printStackTrace();
    }finally{
        try{
            if(st ! =null)
                st.close();
        }catch(SQLException e){
            e.printStackTrace();
        }finally{
            try{
                if(conn ! =null)
                    conn.close();
            }catch(SQLException e){ e.printStackTrace(); }}}}// Modify student information
public void update(Student stu){
    String sql = "UPDATE t_student SET name=? ,age=? WHERE id=?";
    Connection conn = null;
    Statement st = null;
    try{
        //1. Load the registered driver
        Class.forName("com.mysql.jdbc.Driver");
        //2. Obtain the database connection
        conn=DriverManager.getConnection("jdbc:mysql:///jdbc_demo"."root"."root");
        //3. Create statement objects
        PreparedStatement ps = conn.prepareStatement(sql);
        ps.setObject(1,stu.getName());
        ps.setObject(2,stu.getAge());
        ps.setObject(3,stu.getId());
        //4. Execute the SQL statement
        ps.executeUpdate();
        //5. Release resources
    }catch(Exception e){
        e.printStackTrace();
    }finally{
        try{
            if(st ! =null)
                st.close();
        }catch(SQLException e){
            e.printStackTrace();
        }finally{
            try{
                if(conn ! =null)
                    conn.close();
            }catch(SQLException e){ e.printStackTrace(); }}}}Copy the code

The above code works fine, but it duplicates so much that you can extract it and put it in a utility class called JdbcUtil.

/ / tools
public class JdbcUtil {
    private JdbcUtil(a) {}static {
        //1. Load the registered driver
        try {
            Class.forName("com.mysql.jdbc.Driver");
        } catch(Exception e) { e.printStackTrace(); }}public static Connection getConnection(a) {
        try {
            //2. Obtain the database connection
            return DriverManager.getConnection("jdbc:mysql:///jdbc_demo"."root"."root");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    // Release resources
    public static void close(ResultSet rs, Statement st, Connection conn) {
        try {
            if(rs ! =null)
                rs.close();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            try {
                if(st ! =null)
                    st.close();
            } catch (SQLException e) {
                e.printStackTrace();
            } finally {
                try {
                    if(conn ! =null)
                        conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

Copy the code

Simply call the methods in the utility class JdbcUtil directly from the implementation class.


// Add student information
public void save(Student stu) {
    String sql = "INSERT INTO t_student(name,age) VALUES(? ,?) ";
    Connection conn = null;
    PreparedStatement ps=null;
    try {
        conn = JDBCUtil.getConnection();
        //3. Create statement objects
        ps = conn.prepareStatement(sql);
        ps.setObject(1, stu.getName());
        ps.setObject(2, stu.getAge());
        //4. Execute the SQL statement
        ps.executeUpdate();
        //5. Release resources
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        JDBCUtil.close(null, ps, conn); }}// Delete student information
public void delete(Long id) {
    String sql = "DELETE FROM t_student WHERE id=?";
    Connection conn = null;
    PreparedStatement ps = null;
    try {
        conn=JDBCUtil.getConnection();
        //3. Create statement objects
        ps = conn.prepareStatement(sql);
        ps.setObject(1, id);
        //4. Execute the SQL statement
        ps.executeUpdate();
        //5. Release resources
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        JDBCUtil.close(null, ps, conn); }}// Modify student information
public void update(Student stu) {
    String sql = "UPDATE t_student SET name=? ,age=? WHERE id=?";
    Connection conn = null;
    PreparedStatement ps = null;
    try {
        conn=JDBCUtil.getConnection();
        //3. Create statement objects
        ps = conn.prepareStatement(sql);
        ps.setObject(1, stu.getName());
        ps.setObject(2, stu.getAge());
        ps.setObject(3, stu.getId());
        //4. Execute the SQL statement
        ps.executeUpdate();
        //5. Release resources
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        JDBCUtil.close(null, ps, conn); }}public Student get(Long id) {
    String sql = "SELECT * FROM t_student WHERE id=?";
    Connection conn = null;
    Statement st = null;
    ResultSet rs = null;
    PreparedStatement ps=null;
    try {
        conn = JDBCUtil.getConnection();
        //3. Create statement objects
        ps = conn.prepareStatement(sql);
        ps.setObject(1, id);
        //4. Execute the SQL statement
        rs = ps.executeQuery();
        if (rs.next()) {
            String name = rs.getString("name");
            int age = rs.getInt("age");
            Student stu = new Student(id, name, age);
            return stu;
        }
        //5. Release resources
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        JDBCUtil.close(rs, ps, conn);
    }
    return null;
}

public List<Student> list(a) {
    List<Student> list = new ArrayList<>();
    String sql = "SELECT * FROM t_student ";
    Connection conn = null;
    Statement st = null;
    ResultSet rs = null;
    PreparedStatement ps=null;
    try {
        conn=JDBCUtil.getConnection();
        //3. Create statement objects
        ps = conn.prepareStatement(sql);
        //4. Execute the SQL statement
        rs = ps.executeQuery();
        while (rs.next()) {
            long id = rs.getLong("id");
            String name = rs.getString("name");
            int age = rs.getInt("age");
            Student stu = new Student(id, name, age);
            list.add(stu);
        }
        //5. Release resources
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        JDBCUtil.close(rs, ps, conn);
    }
    return list;
}

Copy the code

Although repeated code extraction is completed, the account password in the database is directly displayed in the code, which is not conducive to the maintenance of account password changes in the later period. A db.propertise file can be created to store this information.


driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql:///jdbcdemo
username=root
password=root

Copy the code

Just get the information in the utility class JdbcUtil.


static {
    //1. Load the registered driver
    try {
        ClassLoader loader = Thread.currentThread().getContextClassLoader();
        InputStream inputStream = loader.getResourceAsStream("db.properties");
        p = new Properties();
        p.load(inputStream);
        Class.forName(p.getProperty("driverClassName"));
    } catch(Exception e) { e.printStackTrace(); }}public static Connection getConnection(a) {
    try {
        //2. Obtain the database connection
        return DriverManager.getConnection(p.getProperty("url"), p.getProperty("username"),
        p.getProperty("password"));
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}

Copy the code

The code extraction here seems to have been completed, but in the implementation class, there are still some duplicate code, in the DML operation, except for the SQL and set values of the difference, everything is the same, extract the same part, pass the different part through parameters, can not be directly put in the tool class. At this point, you can create a template class, JdbcTemplate, to create a DML and DQL template to refactor the code.


// Query a unified template
public static List<Student> query(String sql,Object... params){
    List<Student> list=new ArrayList<>();
    Connection conn = null;
    PreparedStatement ps=null;
    ResultSet rs = null;
    try {
        conn=JDBCUtil.getConnection();
        ps=conn.prepareStatement(sql);
        / / set the value
        for (int i = 0; i < params.length; i++) {
            ps.setObject(i+1, params[i]);
        }
        rs = ps.executeQuery();
        while (rs.next()) {
            long id = rs.getLong("id");
            String name = rs.getString("name");
            int age = rs.getInt("age");
            Student stu = new Student(id, name, age);
            list.add(stu);
        }
        //5. Release resources
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        JDBCUtil.close(rs, ps, conn);
    }
    returnlist; } the implementation class simply calls the method.// Add student information
public void save(Student stu) {
    String sql = "INSERT INTO t_student(name,age) VALUES(? ,?) ";
    Object[] params=new Object[]{stu.getName(),stu.getAge()};
    JdbcTemplate.update(sql, params);
}

// Delete student information
public void delete(Long id) {
    String sql = "DELETE FROM t_student WHERE id = ?";
    JdbcTemplate.update(sql, id);
}

// Modify student information
public void update(Student stu) {
    String sql = "UPDATE t_student SET name = ? ,age = ? WHERE id = ?";
    Object[] params=new Object[]{stu.getName(),stu.getAge(),stu.getId()};
    JdbcTemplate.update(sql, params);
}

public Student get(Long id) {
    String sql = "SELECT * FROM t_student WHERE id=?";
    List<Student> list = JDBCTemplate.query(sql, id);
    return list.size()>0? list.get(0) :null;
}

public List<Student> list(a) {
    String sql = "SELECT * FROM t_student ";
    return JDBCTemplate.query(sql);
}

Copy the code

T_student = Student; t_teacher = Student; DQL = Student; Different tables (different objects) should have different columns, and different columns should have different code for handling result sets, which only the DAO knows best. That is, methods for handling results should not be in template methods at all, but should be handled by each DAO itself. Therefore, an IRowMapper interface can be created to process the result set.


public interface IRowMapper {
    // Process the result set
    List rowMapper(ResultSet rs) throws Exception;
}

Copy the code

The DQL template class calls the Handle method in the IRowMapper interface to remind the implementation class to implement the mapping method by itself.


public static List<Student> query(String sql,IRowMapper rsh, Object... params){
    List<Student> list = new ArrayList<>();
    Connection conn = null;
    PreparedStatement ps=null;
    ResultSet rs = null;
    try {
        conn = JdbcUtil.getConnection();
        ps = conn.prepareStatement(sql);
        / / set the value
        for (int i = 0; i < params.length; i++) {
            ps.setObject(i+1, params[i]);
        }
        rs = ps.executeQuery();
        return rsh.mapping(rs);
        //5. Release resources
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        JdbcUtil.close(rs, ps, conn);
    }
    return list ;
}

Copy the code

The implementation class implements the mapping method of the IRowMapper interface and defines what type of data it wants to process.


public Student get(Long id) {
    String sql = "SELECT * FROM t_student WHERE id = ?";
    List<Student> list = JdbcTemplate.query(sql,new StudentRowMapper(), id);
    return list.size()>0? list.get(0) :null;
}
public List<Student> list(a) {
    String sql = "SELECT * FROM t_student ";
    return JdbcTemplate.query(sql,new StudentRowMapper());
}
class StudentRowMapper implements IRowMapper{
    public List mapping(ResultSet rs) throws Exception {
        List<Student> list=new ArrayList<>();
        while(rs.next()){
            long id = rs.getLong("id");
            String name = rs.getString("name");
            int age = rs.getInt("age");
            Student stu=new Student(id, name, age);
            list.add(stu);
        }
        returnlist; }}Copy the code

At this point, the key code to implement ORM is complete, but A DQL query not only looks at student information (of the List type), but also the number of students, which is done through generics.


public interface IRowMapper<T> {
    // Process the result set
    T mapping(ResultSet rs) throws Exception;
}

public static <T> T query(String sql,IRowMapper
       
         rsh, Object... params)
       {
    Connection conn = null;
    PreparedStatement ps=null;
    ResultSet rs = null;
    try {
        conn = JdbcUtil.getConnection();
        ps = conn.prepareStatement(sql);
        / / set the value
        for (int i = 0; i < params.length; i++) {
            ps.setObject(i+1, params[i]);
        }
        rs = ps.executeQuery();
        return rsh.mapping(rs);
        //5. Release resources
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        JdbcUtil.close(rs, ps, conn);
    }
    return null;
}

Copy the code

The code for the StudentRowMapper class is as follows.


class StudentRowMapper implements IRowMapper<List<Student>>{
    public List<Student> mapping(ResultSet rs) throws Exception {
        List<Student> list=new ArrayList<>();
        while(rs.next()){
            long id = rs.getLong("id");
            String name = rs.getString("name");
            int age = rs.getInt("age");
            Student stu=new Student(id, name, age);
            list.add(stu);
        }
        returnlist; }}Copy the code

In this way, you can query not only the List, but also the number of students.


public Long getCount(a){
    String sql = "SELECT COUNT(*) total FROM t_student";
    Long totalCount = (Long) JdbcTemplate.query(sql,
            new IRowMapper<Long>() {
                public Long mapping(ResultSet rs) throws Exception {
                    Long totalCount = null;
                    if(rs.next()){
                        totalCount = rs.getLong("total");
                    }
                    returntotalCount; }});return totalCount;
}

Copy the code

This way, the refactoring design is complete, good code can be easier to maintain in the future, so learning to refactor code is very important.

Classic frameworks use design patterns to solve problems

Spring, for example, is a classic framework that uses design patterns to their fullest. This book will be combined with JDK, Spring, MyBatis, Netty, Tomcat, Dubbo and other classic framework source code analysis of the design pattern, to help you better, more in-depth understanding of the design pattern in the framework of the source code of the ground.

Pay attention to “Tom play architecture” reply to “design pattern” can obtain the complete source code.

Tom play architecture: 30 real cases of design patterns (attached source code), the challenge of annual salary 60W is not a dream

This article is “Tom play structure” original, reproduced please indicate the source. Technology is to share, I share my happiness! If this article is helpful to you, welcome to follow and like; If you have any suggestions can also leave a comment or private letter, your support is my motivation to adhere to the creation. Pay attention to “Tom bomb architecture” for more technical dry goods!