1.场景模拟

使用软件模拟登录控制,普通用户和工作人员用户,工作人员的密码在数据库中是加密的。
步骤大致如下:

前台提交,后台获取登录信息,同数据库中的登陆信息进行比较,只不过工作人员是加密的,普通用户是不加密的。

如果匹配,跳到下一界面,如果不匹配,那么返回登录界面,并且显示错误信息。

代码如下

普通用户:

package demo15.templatemethod.example1;
/**
* 描述用户信息的数据模型
*/
public class UserModel {
private String uuid,userId,pwd,name; public String getUuid() {
return uuid;
} public void setUuid(String uuid) {
this.uuid = uuid;
} public String getUserId() {
return userId;
} public void setUserId(String userId) {
this.userId = userId;
} public String getPwd() {
return pwd;
} public void setPwd(String pwd) {
this.pwd = pwd;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
}
}
*********************************************************************
package demo15.templatemethod.example1;
/**
* 描述登录人员登录时填写的信息的数据模型
*/
public class LoginModel {
private String userId,pwd; public String getUserId() {
return userId;
} public void setUserId(String userId) {
this.userId = userId;
} public String getPwd() {
return pwd;
} public void setPwd(String pwd) {
this.pwd = pwd;
} }
*********************************************************************
package demo15.templatemethod.example1; /**
* 普通用户登录控制的逻辑处理
*/
public class NormalLogin {
/**
* 判断登录数据是否正确,也就是是否能登录成功
* @param lm 封装登录数据的Model
* @return true表示登录成功,false表示登录失败
*/
public boolean login(LoginModel lm) {
//1:从数据库获取登录人员的信息, 就是根据用户编号去获取人员的数据
UserModel um = this.findUserByUserId(lm.getUserId());
//2:判断从前台传递过来的登录数据,和数据库中已有的数据是否匹配
//先判断用户是否存在,如果um为null,说明用户肯定不存在
//但是不为null,用户不一定存在,因为数据层可能返回new UserModel();
//因此还需要做进一步的判断
if (um != null) {
//如果用户存在,检查用户编号和密码是否匹配
if (um.getUserId().equals(lm.getUserId())
&& um.getPwd().equals(lm.getPwd())) {
return true;
}
}
return false;
}
/**
* 根据用户编号获取用户的详细信息
* @param userId 用户编号
* @return 对应的用户的详细信息
*/
private UserModel findUserByUserId(String userId) {
// 这里省略具体的处理,仅做示意,返回一个有默认数据的对象
UserModel um = new UserModel();
um.setUserId(userId);
um.setName("test");
um.setPwd("test");
um.setUuid("User0001");
return um;
}
}

工作人员

package demo15.templatemethod.example2;
/**
* 描述登录人员登录时填写的信息的数据模型
*/
public class LoginModel{
private String workerId,pwd;
public String getWorkerId() {
return workerId;
}
public void setWorkerId(String workerId) {
this.workerId = workerId;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
}
**********************************************************************
package demo15.templatemethod.example2; /**
* 工作人员登录控制的逻辑处理
*/
public class WorkerLogin {
/**
* 判断登录数据是否正确,也就是是否能登录成功
* @param lm 封装登录数据的Model
* @return true表示登录成功,false表示登录失败
*/
public boolean login(LoginModel lm) {
//1:根据工作人员编号去获取工作人员的数据
WorkerModel wm = this.findWorkerByWorkerId(lm.getWorkerId());
//2:判断从前台传递过来的用户名和加密后的密码数据,和数据库中已有的数据是否匹配
//先判断工作人员是否存在,如果wm为null,说明工作人员肯定不存在
//但是不为null,工作人员不一定存在,
//因为数据层可能返回new WorkerModel();因此还需要做进一步的判断
if (wm != null) {
//3:把从前台传来的密码数据,使用相应的加密算法进行加密运算
String encryptPwd = this.encryptPwd(lm.getPwd());
//如果工作人员存在,检查工作人员编号和密码是否匹配
if (wm.getWorkerId().equals(lm.getWorkerId())
&& wm.getPwd().equals(encryptPwd)) {
return true;
}
}
return false;
}
/**
* 对密码数据进行加密
* @param pwd 密码数据
* @return 加密后的密码数据
*/
private String encryptPwd(String pwd){
//这里对密码进行加密,省略了
return pwd;
}
/**
* 根据工作人员编号获取工作人员的详细信息
* @param workerId 工作人员编号
* @return 对应的工作人员的详细信息
*/
private WorkerModel findWorkerByWorkerId(String workerId) {
// 这里省略具体的处理,仅做示意,返回一个有默认数据的对象
WorkerModel wm = new WorkerModel();
wm.setWorkerId(workerId);
wm.setName("Worker1");
wm.setPwd("worker1");
wm.setUuid("Worker0001");
return wm;
}
}
**********************************************************************
package demo15.templatemethod.example2;
/**
* 描述工作人员信息的数据模型
*/
public class WorkerModel {
private String uuid,workerId,pwd,name;
public String getUuid() {
return uuid;
}
public void setUuid(String uuid) {
this.uuid = uuid;
}
public String getWorkerId() {
return workerId;
}
public void setWorkerId(String workerId) {
this.workerId = workerId;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

2.有何问题

1.重复或者相似代码太多了
2.扩展起来很不方便,如果改动一个功能的话,那么两种用户可能都要更改。

3.使用模板方法模式来解决问题

3.1定义

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

3.2模板方法的结构和说明

模板方法就是要抽象出相同或者类似的,找到变与不变的地方,那么就可以使用模板方法模式了。

结构图如下

 

3.3模板方法模式示例代码

package demo15.templatemethod.example3;
/**
* 定义模板方法、原语操作等的抽象类
*/
public abstract class AbstractClass {
/**
* 原语操作1,所谓原语操作就是抽象的操作,必须要由子类提供实现
*/
public abstract void doPrimitiveOperation1();
/**
* 原语操作2
*/
public abstract void doPrimitiveOperation2();
/**
* 模板方法,定义算法骨架
*/
public final void templateMethod() {
doPrimitiveOperation1();
doPrimitiveOperation2();
}
}
********************************************************************
package demo15.templatemethod.example3; /**
* 具体实现类,实现原语操作
*/
public class ConcreteClass extends AbstractClass {
public void doPrimitiveOperation1() {
//具体的实现
}
public void doPrimitiveOperation2() {
//具体的实现
}
}

4.使用模板方法重写示例

4.1LoginModel不变,下面是定义公共的登录控制算法

package demo15.templatemethod.example4;
/**
* 登录控制的模板
*/
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;
}
}

4.2普通用户

package demo15.templatemethod.example4;

/**
* 普通用户登录控制的逻辑处理
*/
public class NormalLogin extends LoginTemplate{
public LoginModel findLoginUser(String loginId) {
// 这里省略具体的处理,仅做示意,返回一个有默认数据的对象
LoginModel lm = new LoginModel();
lm.setLoginId(loginId);
lm.setPwd("testpwd");
return lm;
}
}

4.3工作人员登陆

package demo15.templatemethod.example4;
/**
* 工作人员登录控制的逻辑处理
*/
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;
}
}

4.4客户端使用

package demo15.templatemethod.example4;

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

5.模式讲解

5.1要点

功能:在于固定算法骨架,而让具体算法实现可扩展。

为啥不是接口:接口是一种特殊的抽象类,抽象类不一定包含抽象方法,有抽象方法的一定是抽象类。


什么时候使用抽象类:纪要约束子类的行为,又要为子类提供公共功能


好莱坞法则:不要找我们,我们会联系你。作为父类的模板会在需要的时候调用子类相应的方法,也就是父类来找子类,而不是子类找父类。


模板方法很好的体现了开闭原则和里氏替换原则
java回调技术,就是一种特殊的模板方法模式

5.2本质

固定算法骨架

5.3优缺点

优点:实现代码的复用

缺点:算法骨架不容易升级

设计模式17---设计模式之模板方法模式(Template Method)(行为型)的更多相关文章

  1. 模板方法模式 Template method 行为型 设计模式(二十六)

    模板方法模式 Template method 上图为网上百度的一份简历模板截图   相信大家都有求职的经历,那么必然需要简历,写简历的时候,很可能你会网上检索一份简历模板,使用此模板的格式,然后替换为 ...

  2. 设计模式 ( 十九 ) 模板方法模式Template method(类行为型)

      设计模式 ( 十九 ) 模板方法模式Template method(类行为型) 1.概述 在面向对象开发过程中,通常我们会遇到这样的一个问题:我们知道一个算法所需的关键步骤,并确定了这些步骤的执行 ...

  3. 乐在其中设计模式(C#) - 模板方法模式(Template Method Pattern)

    原文:乐在其中设计模式(C#) - 模板方法模式(Template Method Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 模板方法模式(Template Method ...

  4. 设计模式 - 模板方法模式(template method pattern) JFrame 具体解释

    模板方法模式(template method pattern) JFrame 具体解释 本文地址: http://blog.csdn.net/caroline_wendy 參考模板方法模式(templ ...

  5. 设计模式 - 模板方法模式(template method pattern) 排序(sort) 具体解释

    模板方法模式(template method pattern) 排序(sort) 具体解释 本文地址: http://blog.csdn.net/caroline_wendy 參考模板方法模式(tem ...

  6. 设计模式 - 模板方法模式(template method pattern) 具体解释

    模板方法模式(template method pattern) 详细解释 本文地址: http://blog.csdn.net/caroline_wendy 模板方法模式(template metho ...

  7. 二十四种设计模式:模板方法模式(Template Method Pattern)

    模板方法模式(Template Method Pattern) 介绍定义一个操作中的算法的骨架,而将一些步骤延迟到子类中.Template Method使得子类可以不改变一个算法的结构即可重定义该算法 ...

  8. 模板方法模式(Template Method Pattern)——复杂流程步骤的设计

    模式概述 在现实生活中,很多事情都包含几个实现步骤,例如请客吃饭,无论吃什么,一般都包含点单.吃东西.买单等几个步骤,通常情况下这几个步骤的次序是:点单 --> 吃东西 --> 买单. 在 ...

  9. 模板方法模式-Template Method(Java实现)

    模板方法模式-Template Method 在模板模式中, 处理的流程被定义在父类中, 而具体的处理则交给了子类. 类关系图很简单: Template接口 这里定义了子类需要实现的方法(before ...

  10. 设计模式(九): 从醋溜土豆丝和清炒苦瓜中来学习"模板方法模式"(Template Method Pattern)

    今天是五.四青年节,祝大家节日快乐.看着今天这标题就有食欲,夏天到了,醋溜土豆丝和清炒苦瓜适合夏天吃,好吃不上火.这两道菜大部分人都应该吃过,特别是醋溜土豆丝,作为“鲁菜”的代表作之一更是为大众所熟知 ...

随机推荐

  1. (转)linux下导入、导出mysql数据库命令

    原文链接:http://www.xiaohuai.com/2902 一.导出数据库用mysqldump命令(注意mysql的安装路径,即此命令的路径):1.导出数据和表结构:mysqldump -u用 ...

  2. linux FILE 类型.

    stdio.h 头文件中,有以下内容(用内部行号解释): /* The opaque type of streams. This is the definition used elsewhere. * ...

  3. ajax+ashx 完美实现input file上传文件

    1.input file 样式不能满足需求 <input type="file" value="浏览" /> IE8效果图:    Firefox效 ...

  4. Shell中的数值计算

    #!/bin/bash echo "please input number:" read n a=`expr $n / 100` #a1=`expr $n - $a * 100` ...

  5. The account '' has no team with ID ''

    Xcode 升级到7.2 版本,真机测试的时候报错:The account '' has no team with ID '' 解决办法1:http://stackoverflow.com/quest ...

  6. 使用 phpMyAdmin无法登录mysql的问题

    今天使用使用phpmyadmin时出现了以下错误: (1)第一次时: 当配置文件config.inc.php里的配置项是: $cfg['Servers'][$i]['host'] = 'localho ...

  7. iscroll.js

    <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title&g ...

  8. postgres安装 以及修改postgres 密码

    #postgres安装 apt-get install postgresql-9.3 postgresql-client-9.3 postgresql-contrib-9.3 postgresql-s ...

  9. testng,soket write error错误

    网上解决手段:  testng 工程报错java.net.SocketException SocketException: Software caused connection abort · Iss ...

  10. DACL, NULL or not NULL

    上周 hBifTs在折腾他的文件映射封装类的时候,碰到了不能在 ASP.NET 中直接打开由桌面程序创建的内核对象的问题. 内存映射文件与用户权限 他当时是的方法是修改 ASP.NET 配置文件,让 ...