死磕设计模式-设计模式总览

死磕设计模式-设计模式总览

为什么要学习设计模式

1、能够写出优雅的代码

2、能够帮助我们更好的重构代码

如果用好了设计模式就是架构师,如果用不好设计模式就是码农

回顾一下设计原则

开闭原则

对扩展开放,对修改关闭

单一职责原则

​ 一个类一个接口或者是一个方法,自干一件事

依赖倒置原则

​ 通过抽象使各个类或者模块之间相互不影响,实现松耦合

接口隔离原则定义

​ 尽量保证接口的纯洁性,客户端不应该依赖不需要的接口

迪米特法则

​ 又叫最少知道原则,一个类对其所依赖的类知道的越少越好

里氏替换原则

​ 子类可以扩展父类的功能,但不能改变父类原有的功能

合成复用原则

​ 尽量使用对象组合,聚合,而不使用继承关系达到代码复用的目的

设计模式总览

写出优雅的代码

public void setCurForm(Gw_exammingForm curForm,String parameters)throws BaseException {
      JSONObject jsonObj = new JSONObject(parameters);
      //试卷主键
      if(jsonObj.getString("examinationPaper_id")!= null && (!jsonObj.getString("examinationPaper_id").equals("")))
         curForm.setExaminationPaper_id(jsonObj.getLong("examinationPaper_id"));
      //剩余时间
      if(jsonObj.getString("leavTime") != null && (!jsonObj.getString("leavTime").equals("")))
         curForm.setLeavTime(jsonObj.getInt("leavTime"));
      //单位主键
      if(jsonObj.getString("organization_id")!= null && (!jsonObj.getString("organization_id").equals("")))
         curForm.setOrganization_id(jsonObj.getLong("organization_id"));
      //考试主键
      if(jsonObj.getString("id")!= null && (!jsonObj.getString("id").equals("")))
         curForm.setId(jsonObj.getLong("id"));
      //考场主键
      if(jsonObj.getString("examroom_id")!= null && (!jsonObj.getString("examroom_id").equals("")))
         curForm.setExamroom_id(jsonObj.getLong("examroom_id"));
      //用户主键
      if(jsonObj.getString("user_id")!= null && (!jsonObj.getString("user_id").equals("")))
         curForm.setUser_id(jsonObj.getLong("user_id"));
      //专业
      if(jsonObj.getString("specialtyCode")!= null && (!jsonObj.getString("specialtyCode").equals("")))
         curForm.setSpecialtyCode(jsonObj.getLong("specialtyCode"));
      //岗位
      if(jsonObj.getString("postionCode")!= null && (!jsonObj.getString("postionCode").equals("")))
         curForm.setPostionCode(jsonObj.getLong("postionCode"));
      //等级
      if(jsonObj.getString("gradeCode")!= null && (!jsonObj.getString("gradeCode").equals("")))
         curForm.setGradeCode(jsonObj.getLong("gradeCode"));
      //考试开始时间

      curForm.setExamStartTime(jsonObj.getString("examStartTime"));
      //考试结束时间
      curForm.setExamEndTime(jsonObj.getString("examEndTime"));
      //单选题重要数量
      if(jsonObj.getString("single_selectionImpCount")!= null &&
            (!jsonObj.getString("single_selectionImpCount").equals("")))
         curForm.setSingle_selectionImpCount(jsonObj.getInt("single_selectionImpCount"));
      //多选题重要数量
      if(jsonObj.getString("multi_selectionImpCount")!= null && 
            (!jsonObj.getString("multi_selectionImpCount").equals("")))
          curForm.setMulti_selectionImpCount(jsonObj.getInt("multi_selectionImpCount"));
      //判断题重要数量

      if(jsonObj.getString("judgementImpCount")!= null &&
            (!jsonObj.getString("judgementImpCount").equals("")))
         curForm.setJudgementImpCount(jsonObj.getInt("judgementImpCount"));
      //考试时间
      if(jsonObj.getString("examTime")!= null && (!jsonObj.getString("examTime").equals("")))
         curForm.setExamTime(jsonObj.getInt("examTime"));
      //总分
      if(jsonObj.getString("fullScore")!= null && (!jsonObj.getString("fullScore").equals("")))
         curForm.setFullScore(jsonObj.getLong("fullScore"));
      //及格分

      if(jsonObj.getString("passScore")!= null && (!jsonObj.getString("passScore").equals("")))
         curForm.setPassScore(jsonObj.getLong("passScore"));
      //学员姓名
      curForm.setUserName(jsonObj.getString("user_name"));
      //分数
      if(jsonObj.getString("score")!= null && (!jsonObj.getString("score").equals("")))
         curForm.setScore(jsonObj.getLong("score"));
      //是否及格
      curForm.setResult(jsonObj.getString("result"));
      curForm.setIsPassed(jsonObj.getString("result"));
      //单选答对数量

      if(jsonObj.getString("single_ok_count")!= null && (!jsonObj.getString("single_ok_count").equals("")))
         curForm.setSingle_ok_count(jsonObj.getInt("single_ok_count"));
      //多选答对数量
      if(jsonObj.getString("multi_ok_count")!= null && (!jsonObj.getString("multi_ok_count").equals("")))
         curForm.setMulti_ok_count(jsonObj.getInt("multi_ok_count"));
      //判断答对数量
      if(jsonObj.getString("judgement_ok_count")!= null && (!jsonObj.getString("judgement_ok_count").equals("")))
         curForm.setJudgement_ok_count(jsonObj.getInt("judgement_ok_count"));
}

优化后的代码

public class ExamPaper extends Gw_exammingForm{

   private String examinationPaperId;//试卷主键
   private String leavTime;//剩余时间
   private String organizationId;//单位主键
   private String id;//考试主键
   private String examRoomId;//考场主键
   private String userId;//用户主键
   private String specialtyCode;//专业代码
   private String postionCode;//报考岗位
   private String gradeCode;//报考等级
   private String examStartTime;//考试开始时间
   private String examEndTime;//考试结束时间
   private String singleSelectionImpCount;//单选选题重要数量
   private String multiSelectionImpCount;//多选题重要数量
   private String judgementImpCount;//判断题重要数量
   private String examTime;//考试时长
   private String fullScore;//总分
   private String passScore;//及格分
   private String userName;//学员姓名
   private String score;//考试得分
   private String resut;//是否及格
   private String singleOkCount;//单选题答对数量
   private String multiOkCount;//多选题答对数量
   private String judgementOkCount;//判断题答对数量

}

public void setCurFormpublic void setCurForm(Gw_exammingForm curForm,String parameters)throws BaseException {
   try {
      JSONObject jsonObj = new JSONObject(parameters);
      ExamPaper examPaper = JSONObject.parseObject(parameters,ExamPaper.class);

      curForm = examPaper;

   }catch (Exception e){
      e.printStackTrace();
   }

}

更好的重构

public void save(Student stu){
    String sql="INSERT INTO t_student(name,age) VALUES(?,?)";
    Connection conn=null;
    Statement st=null;
    try{
        // 1. 加载注册驱动
        Class.forName("com.mysql.jdbc.Driver");
        // 2. 获取数据库连接
        conn=DriverManager.getConnection("jdbc:mysql:///jdbcdemo","root","root");
        // 3. 创建语句对象
        PreparedStatement ps=conn.prepareStatement(sql);
        ps.setObject(1,stu.getName());
        ps.setObject(2,stu.getAge());
        // 4. 执行SQL语句
        ps.executeUpdate();
        // 5. 释放资源
    }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();
            }
        }
    }
}

// 删除学生信息
public void delete(Long id){
    String sql="DELETE  FROM t_student WHERE id=?";
    Connection conn=null;
    Statement st=null;
    try{
        // 1. 加载注册驱动
        Class.forName("com.mysql.jdbc.Driver");
        // 2. 获取数据库连接
        conn=DriverManager.getConnection("jdbc:mysql:///jdbcdemo","root","root");
        // 3. 创建语句对象
        PreparedStatement ps=conn.prepareStatement(sql);
        ps.setObject(1,id);
        // 4. 执行SQL语句
        ps.executeUpdate();
        // 5. 释放资源
    }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();
            }
        }
    }
}

// 修改学生信息
public void update(Student stu){
    String sql="UPDATE t_student SET name=?,age=? WHERE id=?";
    Connection conn=null;
    Statement st=null;
    try{
        // 1. 加载注册驱动
        Class.forName("com.mysql.jdbc.Driver");
        // 2. 获取数据库连接
        conn=DriverManager.getConnection("jdbc:mysql:///jdbcdemo","root","root");
        // 3. 创建语句对象
        PreparedStatement ps=conn.prepareStatement(sql);
        ps.setObject(1,stu.getName());
        ps.setObject(2,stu.getAge());
        ps.setObject(3,stu.getId());
        // 4. 执行SQL语句
        ps.executeUpdate();
        // 5. 释放资源
    }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();
            }
        }
    }
}

上面代码功能没有问题,但是代码重复太多了,因此我们可以进行优化,把重复的代码放到一个工具类JdbcUtils里

public class JdbcUtil {
    private JdbcUtil() { }
    static {
        //	1. 加载注册驱动
        try {
            Class.forName("com.mysql.jdbc.Driver");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static Connection getConnection() {
        try {
            // 2. 获取数据库连接
            return DriverManager.getConnection("jdbc:mysql:///jdbcdemo", "root", "root");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    //释放资源
    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();
                }
            }
        }
    }
}

实现类里调用

// 增加学生信息
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. 创建语句对象
        ps = conn.prepareStatement(sql);
        ps.setObject(1, stu.getName());
        ps.setObject(2, stu.getAge());
        // 4. 执行SQL语句
        ps.executeUpdate();
        // 5. 释放资源
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        JDBCUtil.close(null, ps, conn);
    }

}

// 删除学生信息
public void delete(Long id) {
    String sql = "DELETE  FROM t_student WHERE id=?";
    Connection conn = null;
    PreparedStatement ps = null;
    try {
        conn=JDBCUtil.getConnection();
        // 3. 创建语句对象
        ps = conn.prepareStatement(sql);
        ps.setObject(1, id);
        // 4. 执行SQL语句
        ps.executeUpdate();
        // 5. 释放资源
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        JDBCUtil.close(null, ps, conn);
    }

}

// 修改学生信息
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. 创建语句对象
        ps = conn.prepareStatement(sql);
        ps.setObject(1, stu.getName());
        ps.setObject(2, stu.getAge());
        ps.setObject(3, stu.getId());
        // 4. 执行SQL语句
        ps.executeUpdate();
        // 5. 释放资源
    } 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. 创建语句对象
        ps = conn.prepareStatement(sql);
        ps.setObject(1, id);
        // 4. 执行SQL语句
        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. 释放资源
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        JDBCUtil.close(rs, ps, conn);
    }
    return null;
}

public List<Student> list() {
    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. 创建语句对象
        ps = conn.prepareStatement(sql);
        // 4. 执行SQL语句
        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. 释放资源
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        JDBCUtil.close(rs, ps, conn);
    }
    return list;
}

以上代码完成了重复代码的优化,但是数据库中的账号密码等直接显示在代码中,不利于后期账户密码修改,我们可以建立一个db.properties文件来存储这些信息

driverName=com.microsoft.sqlserver.jdbc.SQLServerDriver
userName=sa
passWord=sa
url=jdbc:sqlserver://localhost:1433;DatabaseName=HousDB

只需要在工具类JdbcUtlis中获取

static {
    // 1. 加载注册驱动
    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() {
    try {
        // 2. 获取数据库连接
        return DriverManager.getConnection(p.getProperty("url"), p.getProperty("username"),
        p.getProperty("password"));
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}

​ 百分之80的程序员到这里已经完成代码的优化了

抽取到这里貌似已经完成了,但在实现类中,依赖存在部分重复,在DML操作中,除了SQL和设置值的不同,其他都相同,将相同的抽取出去,不同的部分通过参数传递进啦,无法直接放在工具类中,这时我们可以创建一个模板类JbbcTemplate,创建一个DML和DQL的模板来进行对代码的优化

//查询统一模板
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);
        //设置值
        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. 释放资源
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        JDBCUtil.close(rs, ps, conn);
    }
    return list;
}

实现类直接调用方法

// 增加学生信息
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);
}

// 删除学生信息
public void delete(Long id) {
    String sql = "DELETE FROM t_student WHERE id = ?";
    JdbcTemplate.update(sql, id);
}

// 修改学生信息
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() {
    String sql = "SELECT * FROM t_student ";
    return JDBCTemplate.query(sql);
}

这样重复代码基本就解决了,但又个很严重的问题就是这个程序DQL操作中只能处理Student类和t_studetn表相关数据,无法处理其他类如:Teacher类和t_teacher表。不同表(不同对象),不同表就有不同的列,不同的列处理的结果集就不一样,处理的结果集的操作只有DAO自己最清楚,一件事说,处理结果的方法压根就不应该放在模板中,应该由每个DAO自己来处理。因此我们可以创建IRowMapper接口来处理结果集

public interface IRowMapper {
    //处理结果集
    List rowMapper(ResultSet rs) throws Exception;
}

DQL模板中调用IRowMapper接口中的handle方法提醒实现类去自己实现mapping方法

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);
        //设置值
        for (int i = 0; i < params.length; i++) {
            ps.setObject(i+1, params[i]);
        }
        rs = ps.executeQuery();
        return rsh.mapping(rs);
        // 5. 释放资源
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        JdbcUtil.close(rs, ps, conn);
    }
    return list ;
}

实现类自己去实现IRowMapper接口的Mapping 方法,想要处理什么类型数据在里面自定义即可


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() {
    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);
        }
        return list;
    }
}

好了基本大功告成了,但是DQL查询不单单只有查询学生信息(List类型),还可以查询学生数量,这时就要通过泛型来完成了

public interface IRowMapper<T> {
    //处理结果集
    T rowMapper(ResultSet rs) throws Exception;
}
public static <T> T query(String sql,IRowMapper<T> rsh, Object...params){
    Connection conn = null;
    PreparedStatement ps=null;
    ResultSet rs = null;
    try {
        conn = JdbcUtil.getConnection();
        ps = conn.prepareStatement(sql);
        //设置值
        for (int i = 0; i < params.length; i++) {
            ps.setObject(i+1, params[i]);
        }
        rs = ps.executeQuery();
        return rsh.mapping(rs);
        // 5. 释放资源
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        JdbcUtil.close(rs, ps, conn);
    }
    return null;
}

StudentRowMapper类

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);
        }
        return list;
    }
}

这样不仅可以查询LIst,还可以查询学生数量:

public Long getCount(){
    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");
                    }
                    return totalCount;
                }
            });
    return totalCount;
}

好了重构设计已经完成了,好的代码能够让我们以后维护根方便,因此学会代码重构是非常重要的

推荐书籍 重构 改善既有代码的设计

经典框架都在用的设计模式

Spring就是一个把设计模式用的淋漓尽致的经典框架,其实从类的命名就能看出来

设计模式名称 举例
工厂模式 BeanFactory
装饰器模式 BeanWrapper
代理模式 AopProxy
委派模式 DispatcherServlet
策略模式 HandlerMapping
适配器模式 HandlerAdapter
模板模式 JdbcTemplate
观察者模式 ContextLoaderListener

需要特别声明的,设计模式从来都不是单个设计模式独立使用的。在实际应用中,通常是多个设计模式混合使用,你中有我,我中有你

你可能感兴趣的:(设计模式)