JAVA【设计模式】模板模式

一、定义

在这里插入图片描述

模板模式:指定了一系列的算法骨架(方法实现骨架),将算法的一些步骤延迟到子类中,使得子类在不改变算法结构的情况下,重新定义该算法下面的特定步骤实现。它是一种行为模式

二、示例:

模拟场景:
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关系图

在这里插入图片描述
总结:
通过上⾯的实现可以看到 模版模式 在定义统⼀结构也就是执⾏标准上⾮常⽅便,也就很好的控制了后续的实现者不⽤关⼼调⽤逻辑,按照统⼀⽅式执⾏。那么类的继承者只需要关⼼具体的业务逻辑实现即可。

另外模版模式也是为了解决⼦类通⽤⽅法,放到⽗类中设计的优化。让每⼀个⼦类只做⼦类需要完成的内容,⽽不需要关⼼其他逻辑。这样提取公⽤代码,⾏为由⽗类管理,扩展可变部分,也就⾮常有利于开发拓展和迭代。

posted @ 2022-08-30 22:40  雾托邦  阅读(126)  评论(0编辑  收藏  举报