模板模式
前言:邊動手,邊動腦,才能進步,只動手不動腦,一塌糊涂
定義
又稱模板方法模式,定義一個算法的骨架,并且允許子類為一個或多個步驟提供實現,屬于行為性設計模式
用途
用來梳理流程標準化的業務場景
應用場景
一次性實現一個算法不變的部分,并將可變的部分留給子類去實現
Demo1
以員工從一家公司離職到另一家公司面試并上班為例(假定必須先離職才能去面試)
package com.ns.template.demo1;/*** 找工作類(抽象類,部分方法為protected修飾--保證子類可訪問,部分方法為final修飾--保證方法不被允許修改)*/ public abstract class FindWork {/*** 找工作方法,protected定義保證只有子類才能調用*/protected final void find(){//1.先給當前公司提交離職申請this.applyLeave();//2.審批通過this.approveLeave();//3.拿到離職證明this.getLeaveProve();//4.找到下家要面試的公司this.findCompany();//5.人事面試this.personalInterview();//6.技術面試this.technologyInterview();//7.提交各種資料(不一定是必須的)//在模板模式中,此類方法被稱作鉤子方法,用來靈活的干預流程if(necessary()){submitInformation();}//8.入職this.doWork();}final void doWork() {System.out.println("入職辦理完成,開始上班了");}abstract void submitInformation();protected boolean necessary() {return false;}final void technologyInterview() {System.out.println("技術面試也通過了,準備辦理入職");}final void personalInterview() {System.out.println("物色到一家不錯的公司,人事面試通過了");}final void findCompany() {System.out.println("目前成為了無業人員,開始尋找下家公司");}final void getLeaveProve() {System.out.println("員工拿到離職證明");}final void approveLeave() {System.out.println("公司同意該員工離職");}final void applyLeave(){System.out.println("準備申請離職");} } package com.ns.template.demo1;/*** 普通員工,不需要提交任何入職資料,不需要重寫鉤子方法*/ public class GeneralPerson extends FindWork{@Overridevoid submitInformation() {} } package com.ns.template.demo1;/*** 特殊員工,需要提交入職部分資料,通過重寫鉤子方法*/ public class SpecialPerson extends FindWork{private Boolean necessary;public SpecialPerson(Boolean necessary){this.necessary = necessary;}@Overridevoid submitInformation() {System.out.println("提交離職證明");System.out.println("提交薪資流水單");}@Overrideprotected boolean necessary() {return this.necessary;} } package com.ns.template.demo1;/*** 測試類*/ public class TestTemplate {public static void main(String[] args) {GeneralPerson generalPerson = new GeneralPerson();generalPerson.find();SpecialPerson specialPerson = new SpecialPerson(true);specialPerson.find();} }Demo2
以JDBC連接數據庫的過程為例
package com.ns.template.demo2;import javax.sql.DataSource; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.List;/*** JDBC連接、數據獲取、釋放類*/ public abstract class JdbcTemp {private DataSource dataSource;public JdbcTemp(DataSource dataSource){this.dataSource = dataSource;}public List<?> executeQuery(String sql, RowMapper<?> rowMapper, Object[] values){List<?> result;try {//1.獲取連接,從dataSource中獲取Connection coon = this.getConnection();//2.創建語句集,通過連接對象創建執行語句PreparedStatement pstm = this.createStatement(coon,sql);//3.執行語句集,設置參數并執行ResultSet rs = this.executeSql(pstm,values);//4.處理結果集result = this.parseResultSet(rs,rowMapper);//5.關閉結果集this.closeResultSet(rs);//6.關閉語句集this.closeStatement(pstm);//7.關閉連接this.closeConnection(coon);} catch (SQLException e) {e.printStackTrace();throw new RuntimeException();}return result;}private void closeConnection(Connection coon) throws SQLException {coon.close();}private void closeStatement(PreparedStatement pstm) throws SQLException {pstm.close();}private void closeResultSet(ResultSet rs) throws SQLException {rs.close();}private List<?> parseResultSet(ResultSet rs, RowMapper<?> rowMapper) throws SQLException {List<Object> result = new ArrayList<>();int rowNum = 1;while (rs.next()){result.add(rowMapper.mapRow(rs,rowNum++));}return result;}private ResultSet executeSql(PreparedStatement pstm, Object[] values) throws SQLException {if(values != null){for(int i=0; i<values.length; i++){pstm.setObject(i,values[i]);}}return pstm.executeQuery();}private PreparedStatement createStatement(Connection coon, String sql) throws SQLException {return coon.prepareStatement(sql);}private Connection getConnection() throws SQLException {return this.dataSource.getConnection();} } package com.ns.template.demo2;import java.sql.ResultSet; import java.sql.SQLException;/*** 約束ORM邏輯的接口(實現實體之間映射關系)* @param <T>*/ public interface RowMapper<T> {T mapRow(ResultSet rs, int rowNum) throws SQLException; } package com.ns.template.demo2;/*** 人員實體類*/ public class Person {private String userCode;private String userName;private String password;private int age;public String getUserCode() {return userCode;}public void setUserCode(String userCode) {this.userCode = userCode;}public String getUserName() {return userName;}public void setUserName(String userName) {this.userName = userName;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "Person{" +"userCode='" + userCode + '\'' +", userName='" + userName + '\'' +", password='" + password + '\'' +", age=" + age +'}';} } package com.ns.template.demo2;import javax.sql.DataSource; import java.util.List;/*** 數據庫操作類*/ public class MemberDao extends JdbcTemp {public MemberDao(DataSource dataSource) {super(dataSource);}/*** 此處可擴展,如果把查詢到的字段與實體字段映射起來,而不是一個個get(小小的思考)*/public List<?> select(){String sql = "select * from person";return super.executeQuery(sql, (RowMapper<Person>) (rs, rowNum) -> {Person person = new Person();person.setAge(rs.getInt("age"));person.setPassword(rs.getString("password"));person.setUserCode(rs.getString("user_code"));person.setUserName(rs.getString("user_name"));return person;},null);} } package com.ns.template.demo2;import org.apache.commons.dbcp.BasicDataSource;/*** 將數據源初始化封裝成簡單的單例模式*/ public class DataSourceSingleton {private static BasicDataSource dataSource;private DataSourceSingleton(){}static {dataSource = new BasicDataSource();dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/redis?serverTimezone=UTC");dataSource.setUsername("root");dataSource.setPassword("123456");}public static BasicDataSource getInstance(){return dataSource;} } package com.ns.template.demo2;import java.util.List;/*** 測試類*/ public class TestJdbcTemplate {public static void main(String[] args) {MemberDao memberDao = new MemberDao(DataSourceSingleton.getInstance());List<?> result = memberDao.select();System.out.println(result);} }建表語句
CREATE TABLE `person` (`user_code` varchar(10) DEFAULT NULL COMMENT '用戶代碼',`user_name` varchar(20) DEFAULT NULL COMMENT '用戶名稱',`password` varchar(20) DEFAULT NULL COMMENT '密碼',`age` int(2) DEFAULT NULL COMMENT '年齡' ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='人員表';INSERT INTO `person` VALUES ('1', '測試用戶1', '123456', '1000');總結
優點:
1.將相同處理邏輯放到父類,提高了代碼的復用性
2.將不同的代碼放到子類中處理,提高了代碼的可擴展性
缺點:
1.類數目的增加,每個子類都要去繼承父類,導致類文件數量的增多
2.父類如果添加新的抽象方法,子類都要跟著修改
最后,希望大家都能學以致用!!!
總結
- 上一篇: 8个使用JavaScript展示图片解决
- 下一篇: SGU 160.Magic Multip