5.设计模式-模板模式、适配模式

模板方法模式(Template Method Pattern)

  • 介绍:模板模式通常又叫模板方法模式(Template Method Pattern)是指定义一个算法的骨架,并允许子类为一个或者 多个步骤提供实现
    模板方法使得子类可以在不改变算法结构的情况下,重新定义 算法的某些步骤。
    属于行为性设计模式
  • 使用场景
    1. 一次性实现一个算法的不变的部分,并将可变的行为留给 子类来实现。
    2. 各子类中公共的行为被提取出来并集中到一个公共的父类 中,从而避免代码重复。
  • 优点:
    1. 提高代码的复用性。
    2. 提高代码的扩展性。
    3. 符合开闭原则。
  • 缺点:
    1. 类数目的增加。
    2. 间接地增加了系统实现的复杂度
    3. 继承关系自身缺点,如果父类添加新的抽象方法,所有子 类都要改一遍
//mvn依赖
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.4.1</version>
</dependency>


// 以jdbc 的数据库连接为例
/**
 * 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关键字
        try {
            //1、获取连接
            Connection conn = this.getConnection();
            //2、创建语句集
            PreparedStatement pstm = this.createPrepareStatement(conn,sql);
            //3、执行语句集
            ResultSet rs = this.executeQuery(pstm,values);
            //4、处理结果集
            List<?> result = this.paresResultSet(rs,rowMapper);
            //5、关闭结果集
            this.closeResultSet(rs);
            //6、关闭语句集
            this.closeStatement(pstm);
            //7、关闭连接
            this.closeConnection(conn);
            return result;
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }

    protected void closeConnection(Connection conn) throws Exception {
        //数据库连接池,我们不是关闭
        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)是指将一个类的接口转换成 客户期望的另一个接口,使原本的接口不兼容的类可以一起工作
    属于结构型设计模式。
  • 使用场景
    1. 已经存在的类,它的方法和需求不匹配(方法结果相同或相似) 的情况。
    2. 适配器模式不是软件设计阶段考虑的设计模式,是随着软件维护, 由于不同产品、不同厂家造成功能类似而接口不相同情况下的解决 方案
  • 优点:
    1. 能提高类的透明性和复用,现有的类复用但不需要改变。
    2. 目标类和适配器类解耦,提高程序的扩展性。
    3. 在很多业务场景中符合开闭原则。
  • 缺点:
    1. 适配器编写过程需要全面考虑,可能会增加系统的复杂性
    2. 增加代码阅读难度,降低代码可读性,过多使用适配器会使系统 代码变得凌乱
//以用户登录为例, 账号密码登录,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);

    /**
     * 记住登录状态后自动登录
     * @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);
}



//结合策略模式、工厂模式、适配器模式
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{
            //适配器不一定要实现接口
            LoginAdapter adapter = clazz.newInstance();

            //判断传过来的适配器是否能处理指定的逻辑
            if(adapter.support(adapter)){
                return adapter.login(key,adapter);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }
  
}


// 客户端调用
  public static void main(String[] args) {

        IPassportForThird passportForThird = new PassportForThirdAdapter();

        passportForThird.loginForQQ("");


    }





©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容