type
status
date
slug
summary
tags
category
icon
password
一、定义

模板模式:指定了一系列的算法骨架(方法实现骨架),将算法的一些步骤延迟到子类中,使得子类在不改变算法结构的情况下,重新定义该算法下面的特定步骤实现。它是一种行为模式
二、示例:
模拟场景:
1、模拟爬⾍各类电商商品,⽣成营销推⼴海报场景,⽽整个的爬取过程分为;模拟登录、爬取信息、⽣成海报,这三个步骤。另外每个电商网站的模拟登录、爬取信息、⽣成海报都不一样。
模板模式设计
抽象类,定义了模拟登录、爬取信息、⽣成海报抽象方法,由各大门户不同实现
package com.qf.design.behavior.template.design; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Map; public abstract class NetMall { protected Logger logger = LoggerFactory.getLogger(NetMall.class); //用户id private String uid; //用户密码 private String uPwd; public NetMall(String uid, String uPwd) { this.uid = uid; this.uPwd = uPwd; } /** * 生成商品推广海报 */ public String generateGoodsPoster(String skuUrl){ //1.验证登录 if (!login(uid,uPwd)) return null; //2.爬虫获取网页信息 Map<String, String> reptile = reptile(skuUrl); //3.生成商品海报信息 return createBase64(reptile); } //模拟登录 public abstract Boolean login(String uid, String uPwd); //爬虫获取网页信息 public abstract Map<String,String> reptile(String skuUrl); //生成商品海报信息 public abstract String createBase64(Map<String, String> goodsInfo); }
爬取数据的公共方法
package com.qf.design.behavior.template.design; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; public class HttpClient { public static String doGet(String httpurl) { HttpURLConnection connection = null; InputStream is = null; BufferedReader br = null; String result = null;// 返回结果字符串 try { // 创建远程url连接对象 URL url = new URL(httpurl); // 通过远程url连接对象打开一个连接,强转成httpURLConnection类 connection = (HttpURLConnection) url.openConnection(); // 设置连接方式:get connection.setRequestMethod("GET"); // 设置连接主机服务器的超时时间:15000毫秒 connection.setConnectTimeout(15000); // 设置读取远程返回的数据时间:60000毫秒 connection.setReadTimeout(60000); // 发送请求 connection.connect(); // 通过connection连接,获取输入流 if (connection.getResponseCode() == 200) { is = connection.getInputStream(); // 封装输入流is,并指定字符集 br = new BufferedReader(new InputStreamReader(is, "UTF-8")); // 存放数据 StringBuilder sbf = new StringBuilder(); String temp = null; while ((temp = br.readLine()) != null) { sbf.append(temp); sbf.append("\\r\\n"); } result = sbf.toString(); } } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { // 关闭资源 if (null != br) { try { br.close(); } catch (IOException e) { e.printStackTrace(); } } if (null != is) { try { is.close(); } catch (IOException e) { e.printStackTrace(); } } assert connection != null; connection.disconnect();// 关闭远程连接 } return result; } }
当当
package com.qf.design.behavior.template.design.group; import com.alibaba.fastjson.JSON; import com.qf.design.behavior.template.design.HttpClient; import com.qf.design.behavior.template.design.NetMall; import sun.misc.BASE64Encoder; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.regex.Matcher; import java.util.regex.Pattern; public class DangDangNetMall extends NetMall { public DangDangNetMall(String uid, String uPwd) { super(uid, uPwd); } @Override public Boolean login(String uid, String uPwd) { logger.info("模拟当当⽤户登录 uId:{} uPwd:{}", uid, uPwd); return true; } @Override public Map<String, String> reptile(String skuUrl) { String str = HttpClient.doGet(skuUrl); Pattern p9 = Pattern.compile("(?<=title\\\\>).*(?=</title)"); Matcher m9 = p9.matcher(str); Map<String, String> map = new ConcurrentHashMap<String, String>(); if (m9.find()) { map.put("name", m9.group()); } map.put("price", "4548.00"); logger.info("模拟当当商品爬⾍解析:{} | {} 元 {}", map.get("name"), map.get("price"), skuUrl); return map; } @Override public String createBase64(Map<String, String> goodsInfo) { BASE64Encoder encoder = new BASE64Encoder(); logger.info("模拟⽣成当当商品base64海报"); return encoder.encode(JSON.toJSONString(goodsInfo).getBytes()); } }
JD网
package com.qf.design.behavior.template.design.group; import com.alibaba.fastjson.JSON; import com.qf.design.behavior.template.design.HttpClient; import com.qf.design.behavior.template.design.NetMall; import sun.misc.BASE64Encoder; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.regex.Matcher; import java.util.regex.Pattern; public class JDNetMall extends NetMall { public JDNetMall(String uId, String uPwd){ super(uId, uPwd); } @Override public Boolean login(String uid, String uPwd) { logger.info("模拟京东⽤户登录 uId:{} uPwd:{}", uid, uPwd); return true; } @Override public Map<String, String> reptile(String skuUrl) { String str = HttpClient.doGet(skuUrl); Pattern p9 = Pattern.compile("(?<=title\\\\>).*(?=</title)"); Matcher m9 = p9.matcher(str); Map<String, String> map = new ConcurrentHashMap<String, String>(); if (m9.find()) { map.put("name", m9.group()); } map.put("price", "5999.00"); logger.info("模拟京东商品爬⾍解析:{} | {} 元 {}", map.get("name"), map.get("price"), skuUrl); return map; } @Override public String createBase64(Map<String, String> goodsInfo) { BASE64Encoder encoder = new BASE64Encoder(); logger.info("模拟⽣成京东商品base64海报"); return encoder.encode(JSON.toJSONString(goodsInfo).getBytes()); } }
taobao网
package com.qf.design.behavior.template.design.group; import com.alibaba.fastjson.JSON; import com.qf.design.behavior.template.design.HttpClient; import com.qf.design.behavior.template.design.NetMall; import sun.misc.BASE64Encoder; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.regex.Matcher; import java.util.regex.Pattern; public class TaoBaoNetMall extends NetMall { public TaoBaoNetMall(String uid, String uPwd) { super(uid, uPwd); } @Override public Boolean login(String uid, String uPwd) { logger.info("模拟淘宝⽤户登录 uId:{} uPwd:{}", uid, uPwd); return true; } @Override public Map<String, String> reptile(String skuUrl) { String str = HttpClient.doGet(skuUrl); Pattern p9 = Pattern.compile("(?<=title\\\\>).*(?=</title)"); Matcher m9 = p9.matcher(str); Map<String, String> map = new ConcurrentHashMap<String, String>(); if (m9.find()) { map.put("name", m9.group()); } map.put("price", "4799.00"); logger.info("模拟淘宝商品爬⾍解析:{} | {} 元 {}", map.get("name"), map.get("price"), skuUrl); return map; } @Override public String createBase64(Map<String, String> goodsInfo) { BASE64Encoder encoder = new BASE64Encoder(); logger.info("模拟⽣成淘宝商品base64海报"); return encoder.encode(JSON.toJSONString(goodsInfo).getBytes()); } }
测试:
ApiTest
package com.qf.design.behavior.template.design; import com.qf.design.behavior.template.design.group.DangDangNetMall; import com.qf.design.behavior.template.design.group.JDNetMall; import com.qf.design.behavior.template.design.group.TaoBaoNetMall; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ApiTest { private Logger logger= LoggerFactory.getLogger(ApiTest.class); @Test public void jd_Test(){ NetMall jdNetMall = new JDNetMall("1002001", "1111"); String result = jdNetMall.generateGoodsPoster("<https://item.jd.com/100008348542.html>"); logger.info("测试结果:{}",result); } @Test public void taobao_Test(){ NetMall jdNetMall = new TaoBaoNetMall("1002001", "1111"); String result = jdNetMall.generateGoodsPoster("<https://uland.taobao.com/sem/tbsearch?refpid=mm_26632258_3504122_32538762&keyword=%E6%B7%98%E5%AE%9D&clk1=d50f2fafb28e9f66dc22575a6d3eda87&upsId=d50f2fafb28e9f66dc22575a6d3eda87>"); logger.info("测试结果:{}",result); } @Test public void dd_Test(){ NetMall jdNetMall = new DangDangNetMall("1002001", "1111"); String result = jdNetMall.generateGoodsPoster("<https://product.dangdang.com/25071550.html>"); logger.info("测试结果:{}",result); } }
UML关系图

总结:
通过上⾯的实现可以看到 模版模式 在定义统⼀结构也就是执⾏标准上⾮常⽅便,也就很好的控制了后续的实现者不⽤关⼼调⽤逻辑,按照统⼀⽅式执⾏。那么
类的继承者只需要关⼼具体的业务逻辑实现
即可。
另外模版模式也是为了解决⼦类通⽤⽅法,放到⽗类中设计的优化。让每⼀个⼦类只做⼦类需要完成的内容,⽽不需要关⼼其他逻辑。这样提取公⽤代码,⾏为由⽗类管理,扩展可变部分,也就⾮常有利于开发拓展和迭代。
- 作者:程序员小舟
- 链接:https://codezhou.top/article/JAVA%E3%80%90%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E3%80%91%E6%A8%A1%E6%9D%BF%E6%A8%A1%E5%BC%8F
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
相关文章