首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

模板方式2

2013-12-22 
模板模式216.2? 解决方案16.2.1? 模板方法模式来解决用来解决上述问题的一个合理的解决方案就是模板方法模

模板模式2

16.2? 解决方案

16.2.1? 模板方法模式来解决

用来解决上述问题的一个合理的解决方案就是模板方法模式。那么什么是模板方法模式呢?

(1)模板方法模式定义

?模板方式2

(2)应用模板方法模式来解决的思路

?????? 仔细分析上面的问题,重复或相似代码太多、扩展不方便,出现这些问题的原因在哪里?主要就是两个实现是完全分开、相互独立的,没有从整体上进行控制。如果把两个模块合起来看,就会发现,那些重复或相似的代码就应该被抽取出来,做成公共的功能,而不同的登录控制就可以去扩展这些公共的功能。这样一来,扩展的时候,如果出现有相同的功能,那就直接扩展公共功能就可以了。

?????? 使用模板方法模式,就可以很好的来实现上面的思路。分析上面两个登录控制模块,会发现它们在实现上,有着大致相同的步骤,只是在每步具体的实现上,略微有些不同,因此,可以把这些运算步骤看作是算法的骨架,把具体的不同的步骤实现,延迟到子类去实现,这样就可以通过子类来提供不同的功能实现了。

?????? 经过分析总结,登录控制大致的逻辑判断步骤如下:

  • 根据登录人员的编号去获取相应的数据
  • 获取对登录人员填写的密码数据进行加密后的数据,如果不需要加密,那就是直接返回登录人员填写的密码数据
  • 判断登录人员填写的数据和从数据库中获取的数据是否匹配

    在这三个步骤里面,第一个和第三个步骤是必不可少的,而第二个步骤是可选的。那么就可以定义一个父类,在里面定义一个方法来定义这个算法骨架,这个方法就是模板方法,然后把父类无法确定的实现,延迟到具体的子类来实现就可以了。

    ?????? 通过这样的方式,如果要修改加密的算法,那就在模板的子类里面重新覆盖实现加密的方法就好了,完全不需要去改变父类的算法结构,就可以重新定义这些特定的步骤。

    16.2.2? 模式结构和说明

    模板方法模式的结构如图16.1所示:

    ?模板方式2

    图16.1? 模板方法模式的结构示意图

    AbstractClass

    ?????? 抽象类。用来定义算法骨架和原语操作,具体的子类通过重定义这些原语操作来实现一个算法的各个步骤。在这个类里面,还可以提供算法中通用的实现。

    ConcreteClass

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

    16.2.3? 模板方法模式示例代码

    (1)先来看看AbstractClass的写法,示例代码如下:

    /**

    ?* 定义模板方法、原语操作等的抽象类

    ?*/

    public abstract class AbstractClass {

    ??? /**

    ??? ?* 原语操作1,所谓原语操作就是抽象的操作,必须要由子类提供实现

    ??? ?*/

    ??? public abstract void doPrimitiveOperation1();

    ??? /**

    ??? ?* 原语操作2

    ??? ?*/

    ??? public abstract void doPrimitiveOperation2();

    ??? /**

    ??? ?* 模板方法,定义算法骨架

    ??? ?*/

    ??? public final void templateMethod() {

    ?????? doPrimitiveOperation1();

    ?????? doPrimitiveOperation2();

    ??? }

    }

    (2)再看看具体实现类的写法,示例代码如下:

    /**

    ?* 具体实现类,实现原语操作

    ?*/

    public class ConcreteClass extends AbstractClass {

    ??? public void doPrimitiveOperation1() {

    ?????? //具体的实现

    ??? }

    ??? public void doPrimitiveOperation2() {

    ?????? //具体的实现

    ??? }

    }

    16.2.4? 使用模板方法模式重写示例

    要使用模板方法模式来实现前面的示例,按照模板方法模式的定义和结构,需要定义出一个抽象的父类,在这个父类里面定义模板方法,这个模板方法应该实现进行登录控制的整体的算法步骤。当然公共的功能,就放到这个父类去实现,而这个父类无法决定的功能,就延迟到子类去实现。

    这样一来,两种登录控制就做为这个父类的子类,分别实现自己需要的功能。此时系统的结构如图16.2所示:

    ?模板方式2

    图16.2? 使用模板方法模式实现示例的结构示意图

    (1)为了把原来的两种登录控制统一起来,首先需要把封装登录控制所需要的数据模型统一起来,不再区分是用户编号还是工作人员编号,而是统一称为登录人员的编号,还有把其它用不上的数据去掉,这样就直接使用一个数据模型就可以了。当然,如果各个子类实现需要其它的数据,还可以自行扩展。示例代码如下:

    /**

    ?* 封装进行登录控制所需要的数据

    ?*/

    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;

    ??? }??

    }

    (2)接下来定义公共的登录控制算法骨架,示例代码如下:

    /**

    ?*? 登录控制的模板

    ?*/

    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;

    ??? }

    }

    (3)实现新的普通用户登录控制的逻辑处理,示例代码如下:

    /**

    ?* 普通用户登录控制的逻辑处理

    ?*/

    public class NormalLogin extends LoginTemplate{

    ??? public LoginModel findLoginUser(String loginId) {

    ?????? // 这里省略具体的处理,仅做示意,返回一个有默认数据的对象

    ?????? LoginModel lm = new LoginModel();

    ?????? lm.setLoginId(loginId);

    ?????? lm.setPwd("testpwd");

    ?????? return lm;

    ??? }

    }

    (4)实现新的工作人员登录控制的逻辑处理,示例代码如下:

    /**

    ?* 工作人员登录控制的逻辑处理

    ?*/

    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);

    ??? }

    }

    ?????? 运行结果示例如下:

    使用MD5进行密码加密

    可以登录工作平台=true

    可以进行普通人员登录=false

    ?????? 当然,你可以使用不同的测试数据来测试这个示例。

热点排行