跳至主要內容

【设计模式】行为型-③模板方法模式

holic-x...大约 6 分钟设计模式设计模式

【设计模式】行为型-③模板方法模式

学习核心

  • 模板方法模式核心
    • 概念:抽象类中定义抽象方法的执行顺序和基本策略,子类可以在方法中实现自己的业务逻辑(相当于把业务执行策略安排得明明白白)
      • 父类定义抽象方法执行策略(规定好一系列的执行标准,由这些标准串成一整套业务流程)
    • 组成:抽象父类(抽象模板)、具体子类(策略扩展实现)
      • 抽象父类(抽象模板):定义业务执行顺序和基本策略
      • 具体子类(策略扩展实现):子类可继承基本策略,并且可扩展方法实现
  • 应用场景分析
    • 【电商场景】模拟爬虫电商商品、生成营销推广海报:模拟登录、模拟爬取、生成海报
    • 【OJ】模拟沙箱:OJ 项目中模拟沙箱进行题目解析的步骤设定(构建一个核心的流程执行顺序和基本策略)

概念梳理

​ 模板方法模式:在抽象类中定义了业务的执行顺序和基本策略,然后由其具体的子类根据实际业务需求去重写父类方法进行扩展补充

​ 特点:根据模板定义,保留基本策略、扩展可变策略。模板已经定义了通用结构,使用者只需要关心自己要实现的功能即可

1.抽象类最佳实践-模板设计模式

​ 抽象类的体现是一种模板模式的设计,抽象类作为多个子类的通用模板,子类在抽象类的基础上进行扩展、改造,但子类总体上会保留抽象类的行为方式

模板设计模式能解决的问题:

1)场景分析:当功能内部一部分实现是确定的、一部分实现是不确定的,可以把不确定的部分暴露出去让子类去对应实现

2)实现分析:编写一个抽象父类,父类提供了多个子类的通用方法,并把一个或者多个方法留给子类实现

需求分析

1)有多个类,完成不同的任务job

2)要求统计得到各自完成任务的时间

3)编程实现 TemplateDemo.java

实现思路

1)定义一个TaskTemplate类(定义抽象方法模板job)

2)定义多个子类继承TaskTamplate,并重写job方法完成各自的任务执行操作

// 1.定义抽象模板类
abstract class TaskTemplate{
    // 定义公共抽象方法
    public void job(){
        System.out.println("模板提供的工作方法");
    }
}

// 2.定义多个类继承TaskTemplate重写job实现自定义业务逻辑
class TaskA extends TaskTemplate{
    public void job(){
        // 模拟工作计时(System.currentTimeMillis()获取当前系统时间毫秒数)
        long duration = 100l;
        System.out.println("TaskA 耗时" + duration);
    }

    // 子类自定义其他业务逻辑操作
    public void otherJob(){
        System.out.println("接其他活中....");
    }
}

class TaskB extends TaskTemplate{
    public void job(){
        // 模拟工作计时(System.currentTimeMillis()获取当前系统时间毫秒数)
        long duration = 2000l;
        System.out.println("TaskB 耗时" + duration);
    }
}

class TaskC extends TaskTemplate{
    // TaskC使用父类的job,不自定义
}

public class TemplateDemo {

    public static void main(String[] args) {
        TaskA taskA = new TaskA();
        taskA.job();
        taskA.otherJob();
        TaskB taskB = new TaskB();
        taskB.job();
        TaskC taskC = new TaskC();
        taskC.job();
    }

}

-- output
TaskA 耗时100
接其他活中....
TaskB 耗时2000
模板提供的工作方法

场景分析

1.【电商场景】模拟爬取电商商品,生成营销推广海报

​ 模拟爬取电商商品,生成营销推广海报:模拟爬虫爬取各类商家的商品信息,生成推广海报(海报中带个人邀请码)赚取商品进行返利。基于此可以将业务流程划分为多个步骤:

  • 模拟登录:部分商品只有登录后才能进行爬取,或者如果需要更详细的信息需要登录后才有更多的权限访问
  • 爬取信息:不同的电商平台爬取方式不同、解析方式不同,可以作为实现类中的特定实现
  • 生成海报:生成相应电商平台的海报信息(可以特色化设定商品来源标识等)

代码实现参考

  • 抽象模板类定义
/**
 * 模板模式应用
 * [电商场景]:爬虫爬取商品信息,模拟生成营销海报信息
 * - 模拟登录
 * - 模拟爬取
 * - 生成营销海报
 */
@Data
public abstract class NetMallTemplate {

    // 登录用户名、密码设定
    private String userAccount;
    private String password;

    // 构造器定义
    NetMallTemplate(String userAccount, String password) {
        this.userAccount = userAccount;
        this.password = password;
    }

    /**
     * 模板方法定义:约定执行流程和基本策略(可以理解为定义业务执行的程序入口)
     * 1.模拟登录
     * 2.模拟爬取
     * 3.生成营销海报
     */
    public String generatePoster(String skuUrl){
        // 模拟登录
        boolean loginFlag = login(userAccount,password);
        // 登录成功,进行数据爬取
        if(loginFlag){
            // 爬取数据
            Map<String,String> goodsInfo = crawl(skuUrl);
            // 生成海报信息
            return createBase64(goodsInfo);
        }else{
            return null;
        }
    }

    // 模拟登录
    public abstract boolean login(String userAccount, String password);

    // 模拟爬取提取商品信息
    public abstract Map<String,String> crawl(String skuUrl);

    // 生成营销海报
    public abstract String createBase64(Map<String,String> goodsInfo) ;

}
  • 子类实现(京东、淘宝等电商平台)
/**
 * 京东平台
 */
public class JingDongNetMall extends NetMallTemplate{

    JingDongNetMall(String userAccount, String password) {
        super(userAccount, password);
    }

    @Override
    public boolean login(String userAccount, String password) {
        System.out.println("模拟京东网站登录:" + userAccount);
        return true;
    }

    @Override
    public Map<String, String> crawl(String skuUrl) {
        // 模拟根据URL爬取商品信息、解析,随后返回商品信息(参考实现:根据指定URL获取响应信息,然后解析相关的参数信息)
        System.out.println("【京东】模拟爬虫,根据url爬取商品信息");
        Map<String, String> map = new HashMap<>();
        map.put("name", "小米手机");
        map.put("skuPrice", "10000");
        map.put("skuUrl", skuUrl);
        return map;
    }

    @Override
    public String createBase64(Map<String, String> goodsInfo) {
        // 根据商品信息生成相应的营销海报
        BASE64Encoder encoder = new BASE64Encoder();
        System.out.println("京东商品base64海报生成");
        return encoder.encode(JSON.toJSONString(goodsInfo).getBytes(StandardCharsets.UTF_8));
    }
}

/**
 * 淘宝平台
 */
public class TaobaoNetMall extends NetMallTemplate{

    TaobaoNetMall(String userAccount, String password) {
        super(userAccount, password);
    }

    @Override
    public boolean login(String userAccount, String password) {
        System.out.println("模拟淘宝网站登录:" + userAccount);
        return true;
    }

    @Override
    public Map<String, String> crawl(String skuUrl) {
        // 模拟根据URL爬取商品信息、解析,随后返回商品信息(参考实现:根据指定URL获取响应信息,然后解析相关的参数信息)
        System.out.println("【淘宝】模拟爬虫,根据url爬取商品信息");
        Map<String, String> map = new HashMap<>();
        map.put("name", "acer 电脑");
        map.put("skuPrice", "39999");
        map.put("skuUrl", skuUrl);
        return map;
    }

    @Override
    public String createBase64(Map<String, String> goodsInfo) {
        // 根据商品信息生成相应的营销海报
        BASE64Encoder encoder = new BASE64Encoder();
        System.out.println("淘宝商品base64海报生成");
        return encoder.encode(JSON.toJSONString(goodsInfo).getBytes(StandardCharsets.UTF_8));
    }
}
  • 客户端测试
/**
 * 模拟客户端:测试营销海报生成
 */
public class NetMallClient {
    public static void main(String[] args) {
        // 京东海报生成
        JingDongNetMall jingDongNetMall = new JingDongNetMall("noob","123456");
        System.out.println(jingDongNetMall.generatePoster("http://jingdong.com/xxx"));

        // 淘宝海报生成
        TaobaoNetMall taobaoNetMall = new TaobaoNetMall("007","123456");
        System.out.println(taobaoNetMall.generatePoster("http://taobao.com/xxx"));
    }
}

-- output
模拟京东网站登录:noob
【京东】模拟爬虫,根据url爬取商品信息
京东商品base64海报生成
eyJza3VVcmwiOiJodHRwOi8vamluZ2RvbmcuY29tL3h4eCIsIm5hbWUiOiLlsI/nsbPmiYvmnLoi
LCJza3VQcmljZSI6IjEwMDAwIn0=
    
模拟淘宝网站登录:007
【淘宝】模拟爬虫,根据url爬取商品信息
淘宝商品base64海报生成
eyJza3VVcmwiOiJodHRwOi8vdGFvYmFvLmNvbS94eHgiLCJuYW1lIjoiYWNlciDnlLXohJEiLCJz
a3VQcmljZSI6IjM5OTk5In0=
评论
  • 按正序
  • 按倒序
  • 按热度
Powered by Waline v3.1.3