模板方法模式(Template Method)

来源:互联网 发布:知乎女神阿子车 编辑:程序博客网 时间:2024/05/16 12:26

1. 模式的定义

在应用系统中,需要登录控制的功能。

模板方法模式的定义:
定义一个操作中的算法的骨架,而将一些步骤延迟到子类中,模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

2. UML图

这里写图片描述

AbstractClass:抽象类,用来定义算法骨架和原语操作,具体的子类通过重定义这些原语操作来实现一个算法的各个步骤。

ConcreteClass:具体实现类,用来实现算法骨架中的某些步骤,完成与特定子类相关的功能

代码:

/** * 封装进行登录控制所需要的数据 */public class LoginModel {    /**     * 登录人员的编号,通用的,可能是用户编号,也可能是工作人员编号     */    private String loginId;    /**     * 登录的密码     */    private String pwd;    public String getLoginId() {        return loginId;    }    public void setLoginId(String loginId) {        this.loginId = loginId;    }    public String getPwd() {        return pwd;    }    public void setPwd(String pwd) {        this.pwd = pwd;    }   }/** *  登录控制的模板 */public abstract class LoginTemplate {    /**     * 判断登录数据是否正确,也就是是否能登录成功     * @param lm 封装登录数据的Model     * @return true表示登录成功,false表示登录失败     */    public final boolean login(LoginModel lm){        //1:根据登录人员的编号去获取相应的数据        LoginModel dbLm = this.findLoginUser(lm.getLoginId());        if(dbLm!=null){            //2:对密码进行加密            String encryptPwd = this.encryptPwd(lm.getPwd());            //把加密后的密码设置回到登录数据模型里面            lm.setPwd(encryptPwd);            //3:判断是否匹配            return this.match(lm, dbLm);        }        return false;    }    /**     * 根据登录编号来查找和获取存储中相应的数据     * @param loginId 登录编号     * @return 登录编号在存储中相对应的数据     */    public abstract LoginModel findLoginUser(String loginId);    /**     * 对密码数据进行加密     * @param pwd 密码数据     * @return 加密后的密码数据     */    public String encryptPwd(String pwd){        return pwd;    }    /**     * 判断用户填写的登录数据和存储中对应的数据是否匹配得上     * @param lm 用户填写的登录数据     * @param dbLm 在存储中对应的数据     * @return true表示匹配成功,false表示匹配失败     */    public boolean match(LoginModel lm,LoginModel dbLm){        if(lm.getLoginId().equals(dbLm.getLoginId())                 && lm.getPwd().equals(dbLm.getPwd())){            return true;        }        return false;    }}/** * 普通用户登录控制的逻辑处理 */public class NormalLogin extends LoginTemplate{    public LoginModel findLoginUser(String loginId) {        // 这里省略具体的处理,仅做示意,返回一个有默认数据的对象        LoginModel lm = new LoginModel();        lm.setLoginId(loginId);        lm.setPwd("testpwd");        return lm;    }}/** * 工作人员登录控制的逻辑处理 */public class WorkerLogin extends LoginTemplate{    public LoginModel findLoginUser(String loginId) {        // 这里省略具体的处理,仅做示意,返回一个有默认数据的对象        LoginModel lm = new LoginModel();        lm.setLoginId(loginId);        lm.setPwd("workerpwd");        return lm;    }    public String encryptPwd(String pwd){        //覆盖父类的方法,提供真正的加密实现        //这里对密码进行加密,比如使用:MD5、3DES等等,省略了        System.out.println("使用MD5进行密码加密");        return pwd;    }}public class Client {    public static void main(String[] args) {        //准备登录人的信息        LoginModel lm = new LoginModel();        lm.setLoginId("admin");        lm.setPwd("workerpwd");        //准备用来进行判断的对象        LoginTemplate lt = new WorkerLogin();        LoginTemplate lt2 = new NormalLogin();        //进行登录测试        boolean flag = lt.login(lm);        System.out.println("可以登录工作平台="+flag);        boolean flag2 = lt2.login(lm);        System.out.println("可以进行普通人员登录="+flag2);    }}

3. 研磨设计模式

1)模板方法模式的功能
在于固定算法骨架,而让具体实现可扩展

2)既要约束子类的行为,又要为子类提供公共功能 –> 使用抽象类

3)Java的动态绑定:对于出现子类覆盖父类方法的情况,在编译时是看数据类型,运行时则看实际的对象类型

4)Java回调技术
通过回调在接口中定义的方法,调用到具体的实现类中的方法,本质也是利用Java的动态绑定技术

/** * 封装进行登录控制所需要的数据 */public class LoginModel {    /**     * 登录人员的编号,通用的,可能是用户编号,也可能是工作人员编号     */    private String loginId;    /**     * 登录的密码     */    private String pwd;    public String getLoginId() {        return loginId;    }    public void setLoginId(String loginId) {        this.loginId = loginId;    }    public String getPwd() {        return pwd;    }    public void setPwd(String pwd) {        this.pwd = pwd;    }   }/** * 登录控制的模板方法需要的回调接口, * 需要尽可能的把所有需要的接口方法都定义出来, * 或者说是所有可以被扩展的方法都需要被定义出来 */public interface LoginCallback {    /**     * 根据登录编号来查找和获取存储中相应的数据     * @param loginId 登录编号     * @return 登录编号在存储中相对应的数据     */    public LoginModel findLoginUser(String loginId);    /**     * 对密码数据进行加密     * @param pwd 密码数据     * @param template LoginTemplate对象,通过它来调用在     *              LoginTemplate中定义的公共方法或缺省实现     * @return 加密后的密码数据     */    public String encryptPwd(String pwd,LoginTemplate template);    /**     * 判断用户填写的登录数据和存储中对应的数据是否匹配得上     * @param lm 用户填写的登录数据     * @param dbLm 在存储中对应的数据     * @param template LoginTemplate对象,通过它来调用在     *              LoginTemplate中定义的公共方法或缺省实现     * @return true表示匹配成功,false表示匹配失败     */    public boolean match(LoginModel lm,LoginModel dbLm,LoginTemplate template);}/** *  登录控制的模板 */public class LoginTemplate {    /**     * 判断登录数据是否正确,也就是是否能登录成功     * @param lm 封装登录数据的Model     * @param callback LoginCallback对象     * @return true表示登录成功,false表示登录失败     */    public final boolean login(LoginModel lm,LoginCallback callback){        //1:根据登录人员的编号去获取相应的数据        LoginModel dbLm = callback.findLoginUser(lm.getLoginId());        if(dbLm!=null){            //2:对密码进行加密            String encryptPwd = callback.encryptPwd(lm.getPwd(),this);            //把加密后的密码设置回到登录数据模型里面            lm.setPwd(encryptPwd);            //3:判断是否匹配            return callback.match(lm, dbLm,this);        }        return false;    }    /**     * 对密码数据进行加密     * @param pwd 密码数据     * @return 加密后的密码数据     */    public String encryptPwd(String pwd){        return pwd;    }    /**     * 判断用户填写的登录数据和存储中对应的数据是否匹配得上     * @param lm 用户填写的登录数据     * @param dbLm 在存储中对应的数据     * @return true表示匹配成功,false表示匹配失败     */    public boolean match(LoginModel lm,LoginModel dbLm){        if(lm.getLoginId().equals(dbLm.getLoginId())                 && lm.getPwd().equals(dbLm.getPwd())){            return true;        }        return false;    }}public class Client {    public static void main(String[] args) {        //准备登录人的信息        LoginModel lm = new LoginModel();        lm.setLoginId("admin");        lm.setPwd("workerpwd");        //准备用来进行判断的对象        LoginTemplate lt = new LoginTemplate();        //进行登录测试,先测试普通人员登录        boolean flag = lt.login(lm,new LoginCallback(){            public String encryptPwd(String pwd, LoginTemplate template) {                //自己不需要,直接转调模板中的默认实现                return template.encryptPwd(pwd);            }            public LoginModel findLoginUser(String loginId) {                // 这里省略具体的处理,仅做示意,返回一个有默认数据的对象                LoginModel lm = new LoginModel();                lm.setLoginId(loginId);                lm.setPwd("testpwd");                return lm;            }            public boolean match(LoginModel lm, LoginModel dbLm,                    LoginTemplate template) {                //自己不需要覆盖,直接转调模板中的默认实现                return template.match(lm, dbLm);            }        });        System.out.println("可以进行普通人员登录="+flag);        //测试工作人员登录        boolean flag2 = lt.login(lm,new LoginCallback(){            public String encryptPwd(String pwd, LoginTemplate template) {                //覆盖父类的方法,提供真正的加密实现                //这里对密码进行加密,比如使用:MD5、3DES等等,省略了                System.out.println("使用MD5进行密码加密");                return pwd;            }            public LoginModel findLoginUser(String loginId) {                // 这里省略具体的处理,仅做示意,返回一个有默认数据的对象                LoginModel lm = new LoginModel();                lm.setLoginId(loginId);                lm.setPwd("workerpwd");                return lm;            }            public boolean match(LoginModel lm, LoginModel dbLm,                    LoginTemplate template) {                //自己不需要覆盖,直接转调模板中的默认实现                return template.match(lm, dbLm);            }        });             System.out.println("可以登录工作平台="+flag2);    }}

5)模板方法模式的本质:固定算法骨架
模板方法模式主要是通过制定模板,把算法步骤固定下来,至于谁来实现,模板可以自己提供实现,也可以由子类去实现,还可以通过回调机制让其他类来实现。

0 0
原创粉丝点击