模板方法模式(Template Method Pattern)
- 介紹:模板模式通常又叫模板方法模式(Template Method Pattern)是指定義一個算法的骨架官疲,并允許子類為一個或者 多個步驟提供實現(xiàn)
模板方法使得子類可以在不改變算法結(jié)構(gòu)的情況下拙已,重新定義 算法的某些步驟淫茵。
屬于行為性設(shè)計模式
- 使用場景
- 一次性實現(xiàn)一個算法的不變的部分,并將可變的行為留給 子類來實現(xiàn)页眯。
- 各子類中公共的行為被提取出來并集中到一個公共的父類 中梯捕,從而避免代碼重復。
- 優(yōu)點:
- 提高代碼的復用性窝撵。
- 提高代碼的擴展性傀顾。
- 符合開閉原則。
- 缺點:
- 類數(shù)目的增加碌奉。
- 間接地增加了系統(tǒng)實現(xiàn)的復雜度
- 繼承關(guān)系自身缺點短曾,如果父類添加新的抽象方法,所有子 類都要改一遍
//mvn依賴
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.1</version>
</dependency>
// 以jdbc 的數(shù)據(jù)庫連接為例
/**
* ORM映射定制化的接口
*/
public interface RowMapper<T> {
T mapRow(ResultSet rs,int rowNum) throws Exception;
}
//模板
public abstract class JdbcTemplate {
private DataSource dataSource;
public JdbcTemplate(DataSource dataSource) {
this.dataSource = dataSource;
}
public List<?> executeQuery(String sql, RowMapper<?> rowMapper, Object[] values){
//TODO 以下方法子類集成使用的 ,若不允許子類修改赐劣,可以添加fianl關(guān)鍵字
try {
//1嫉拐、獲取連接
Connection conn = this.getConnection();
//2、創(chuàng)建語句集
PreparedStatement pstm = this.createPrepareStatement(conn,sql);
//3隆豹、執(zhí)行語句集
ResultSet rs = this.executeQuery(pstm,values);
//4椭岩、處理結(jié)果集
List<?> result = this.paresResultSet(rs,rowMapper);
//5、關(guān)閉結(jié)果集
this.closeResultSet(rs);
//6璃赡、關(guān)閉語句集
this.closeStatement(pstm);
//7判哥、關(guān)閉連接
this.closeConnection(conn);
return result;
}catch (Exception e){
e.printStackTrace();
}
return null;
}
protected void closeConnection(Connection conn) throws Exception {
//數(shù)據(jù)庫連接池,我們不是關(guān)閉
conn.close();
}
protected void closeStatement(PreparedStatement pstm) throws Exception {
pstm.close();
}
protected void closeResultSet(ResultSet rs) throws Exception {
rs.close();
}
protected List<?> paresResultSet(ResultSet rs, RowMapper<?> rowMapper) throws Exception {
List<Object> result = new ArrayList<Object>();
int rowNum = 1;
while (rs.next()){
result.add(rowMapper.mapRow(rs,rowNum ++));
}
return result;
}
protected ResultSet executeQuery(PreparedStatement pstm, Object[] values) throws Exception {
for (int i = 0; i < values.length; i++) {
pstm.setObject(i,values[i]);
}
return pstm.executeQuery();
}
protected PreparedStatement createPrepareStatement(Connection conn, String sql) throws Exception {
return conn.prepareStatement(sql);
}
public Connection getConnection() throws Exception {
return this.dataSource.getConnection();
}
}
//entity
public class User {
private String uid;
private String username;
private int age;
private String addr;
// setget()
}
//Dao
public class UserDao extends JdbcTemplate {
public UserDao(DataSource dataSource) {
super(dataSource);
}
public List<?> selectAll(){
String sql = "select * from t_user";
return super.executeQuery(sql, new RowMapper<User>() {
public User mapRow(ResultSet rs, int rowNum) throws Exception {
User member = new User();
//字段過多碉考,可使用原型模式
member.setUid(rs.getString("uid"));
member.setUsername(rs.getString("username"));
member.setAge(rs.getInt("age"));
member.setAddr(rs.getString("addr"));
return member;
}
},null);
}
}
適配器模式(Adapter Pattern)
- 介紹:適配器模式(Adapter Pattern)是指將一個類的接口轉(zhuǎn)換成 客戶期望的另一個接口塌计,使原本的接口不兼容的類可以一起工作
屬于結(jié)構(gòu)型設(shè)計模式。
- 使用場景
- 已經(jīng)存在的類侯谁,它的方法和需求不匹配(方法結(jié)果相同或相似) 的情況锌仅。
- 適配器模式不是軟件設(shè)計階段考慮的設(shè)計模式章钾,是隨著軟件維護, 由于不同產(chǎn)品热芹、不同廠家造成功能類似而接口不相同情況下的解決 方案
- 優(yōu)點:
- 能提高類的透明性和復用贱傀,現(xiàn)有的類復用但不需要改變。
- 目標類和適配器類解耦伊脓,提高程序的擴展性府寒。
- 在很多業(yè)務(wù)場景中符合開閉原則。
- 缺點:
- 適配器編寫過程需要全面考慮报腔,可能會增加系統(tǒng)的復雜性
- 增加代碼閱讀難度株搔,降低代碼可讀性,過多使用適配器會使系統(tǒng) 代碼變得凌亂
//以用戶登錄為例, 賬號密碼登錄,qq登錄纯蛾,微信登錄等 (策略 纤房、工廠、適配器)
//entity
public class User {
private String username;
private String password;
private String mid;
private String info;
//setget() ...
}
//result Entity
public class ResultMsg {
private int code;
private String msg;
private Object data;
//setget() ...
}
//adapter
/**
* 在適配器里面翻诉,這個接口是可有可無炮姨,不要跟模板模式混淆
* 模板模式一定是抽象類,而這里僅僅只是一個接口
* Created by Tom on 2019/3/16.
*/
public interface LoginAdapter {
boolean support(Object adapter);
ResultMsg login(String id,Object adapter);
}
//qq 登錄
public class LoginForQQAdapter implements LoginAdapter {
public boolean support(Object adapter) {
return adapter instanceof LoginForQQAdapter;
}
public ResultMsg login(String id, Object adapter) {
return ew ResultMsg(200,"登錄成功",id + ": 恭喜登錄成功");;
}
}
// 微信登錄
public class LoginForWechatAdapter implements LoginAdapter {
public boolean support(Object adapter) {
return adapter instanceof LoginForWechatAdapter;
}
public ResultMsg login(String id, Object adapter) {
return null;
}
}
//其他登錄方式 token碰煌、微博等等
......
// 登錄方法
public class SiginService {
/**
* 注冊方法
* @param username
* @param password
* @return
*/
public ResultMsg regist(String username,String password){
return new ResultMsg(200,"注冊成功",new Member());
}
/**
* 登錄的方法
* @param username
* @param password
* @return
*/
public ResultMsg login(String username,String password){
return new ResultMsg(200,"登錄成功",username + ": 恭喜登錄成功");
}
}
/**
* 只擴展
*/
public interface IPassportForThird {
/**
* QQ登錄
* @param id
* @return
*/
ResultMsg loginForQQ(String id);
/**
* 微信登錄
* @param id
* @return
*/
ResultMsg loginForWechat(String id);
/**
* 記住登錄狀態(tài)后自動登錄
* @param token
* @return
*/
ResultMsg loginForToken(String token);
/**
* 手機號登錄
* @param telphone
* @param code
* @return
*/
ResultMsg loginForTelphone(String telphone, String code);
/**
* 注冊后自動登錄
* @param username
* @param passport
* @return
*/
ResultMsg loginForRegist(String username, String passport);
}
//結(jié)合策略模式剑令、工廠模式、適配器模式
public class PassportForThirdAdapter extends SiginService implements IPassportForThird {
public ResultMsg loginForQQ(String id) {
// return processLogin(id,RegistForQQAdapter.class);
return processLogin(id,LoginForQQAdapter.class);
}
public ResultMsg loginForWechat(String id) {
return processLogin(id,LoginForWechatAdapter.class);
}
public ResultMsg loginForToken(String token) {
return processLogin(token,LoginForTokenAdapter.class);
}
public ResultMsg loginForTelphone(String telphone, String code) {
return processLogin(telphone,LoginForTelAdapter.class);
}
public ResultMsg loginForRegist(String username, String passport) {
super.regist(username,passport);
return super.login(username,passport);
}
private ResultMsg processLogin(String key,Class<? extends LoginAdapter> clazz){
try{
//適配器不一定要實現(xiàn)接口
LoginAdapter adapter = clazz.newInstance();
//判斷傳過來的適配器是否能處理指定的邏輯
if(adapter.support(adapter)){
return adapter.login(key,adapter);
}
}catch (Exception e){
e.printStackTrace();
}
return null;
}
}
// 客戶端調(diào)用
public static void main(String[] args) {
IPassportForThird passportForThird = new PassportForThirdAdapter();
passportForThird.loginForQQ("");
}