栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

【java设计模式】(10)---模版方法模式(案例解析)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【java设计模式】(10)---模版方法模式(案例解析)

一、概念

1、概念

模板方法模式是一种基于继承的代码复用技术,它是一种类行为型模式。

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

2、举例理解

网上举了一个请客吃饭的例子,我觉得解释的挺好的。我们每个人去请客吃饭。一般都含三个步骤:点单、吃东西、买单,而且顺序就是从做左到右的。

在这三个步骤中,点单和买单大同小异,最大的区别在于第二步——吃什么?吃面条和吃满汉全席可大不相同,如图1所示

所以从开发角度来分析,有时也会遇到类似的情况,某个方法的实现需要多个步骤(类似“ 请客 ”),其中有些步骤是固定的(类似“点单”和“买单”),而有些步骤并不固定,存在

可变性(类似“吃东西”)。

为了提高代码的复用性和系统的灵活性,我们把"点单"和"买单"的实现放在父类中实现,而对于"吃东西",因为差异性就很大所以在父类中只做一个声明,将其具体实现放在不同的

子类中,在一个子类中提供“吃面条”的实现,而另一个子类提供“吃满汉全席”的实现。通过使用模板方法模式,一方面提高了代码的复用性,另一方面还可以利用面向对象的多态性,

在运行时选择一种具体子类,实现完整的“请客”方法,提高系统的灵活性和可扩展性。

3、结构和说明

AbstractClass:抽象类。用来定义算法骨架和原语操作,在这个类里面,还可以提供算法中通用的实现

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

public abstract class AbstractClass {

    
    private final void order(){
     //点餐
    }
    
    public abstract void eatSomething();
    
    private final void settlement(){
    //结算
    } 
    
    protected final void workOneDay()
    {
       //点单
        order();
        //吃东西
        eatSomething();
        //结单
        settlement();
    }
    
   
    protected boolean isNeedWc()
    {
        return false;
    }
}

子类这里就不写了。

4、优缺点

优点

  • 封装不变,扩展可变:父类封装了具体流程以及实现部分不变行为,其它可变行为交由子类进行具体实现;
  • 流程由父类控制,子类进行实现:框架流程由父类限定,子类无法更改;子类可以针对流程某些步骤进行具体实现;

缺点

抽象规定了行为,具体负责实现,与通常事物的行为相反,会带来理解上的困难(通俗地说,“父类调用了子类方法”);

5、应用场景

  • 多个子类有公有的方法,并且逻辑基本相同时;
  • 重要,复杂的算法,可以把核心算法设计为模板方法,周边的相关细节功能则由各个子类实现;
  • 重构时,模板方法模式是一个经常使用的模式,把相同的代码抽取到父类,然后通过钩子函数约束其行为;

二、模版方法模式实战示例

之前在参与一个app后段开发,里面有个资讯模块。这个模版的内容不是我们工作人员进行编辑,而是通过爬虫去获取各大网站的资讯,然后处理好后存入我们的数据库。

之前大概爬了十几个网站的资讯。这里的业务流程是这样的 1、爬取资讯内容->2、校验是否已经抓取过->3、存储内容。

这里只有第一步是需要子类去实现的,因为每个网站的数据格式都是不一样的,所以我们需要子类爬取后,统一处理成我们的格式。那么第二步第三步是可以通过父类完成的。

这里代码如下。

1、抽象类

抽象类

@Slf4j
public abstract class AbstractCrawlNewsService {

   
    protected abstract List crawlPage(int pageNum) throws IOException;

    
    protected final Map isCrawled(List checkParams){
        //数据库校验
        return new HashMap<>();
    }

    
    protected final void saveArticle(Object object){
        //保存数据库
    }

    
    protected void doTask(String url) {
        int pageNum = 1;
        while (true) {
            //1、爬取网站数据,因为网站不可能一次性获取所以资讯数据的 所以进行分页查询 默认第一页开始
            List newsList = crawlPage(pageNum++);
            // 抓取不到新的内容本次抓取结束
            if (CollectionUtils.isEmpty(newsList)) {
                break;
            }
            //2、校验是否已经抓取过滤(查询我们自己数据库)
            Map crawledMap = isCrawled(newsList);

             //3、将数据保存数据库
            for (int i = newsList.size() - 1; i >= 0; i--) {
                Object object = newsList.get(i);
                // 没有爬取过,才进行爬取
                if (!crawledMap.getOrDefault(object.getTitle(), false)) {
                    saveArticle(object);
                }
            }
            //可以考虑请求后休眠以下 因为太频繁IP容易被封。
            ThreadUtils.sleep(2);
        }
    }   
}
 

2、具体实现类

接口

public interface CrawlerHuoXingService {

    void start();
}

实现类

@Slf4j
@Service
public class CrawlerHuoXingServiceImpl extends AbstractCrawlNewsService
        implements CrawlerHuoXingService {

    
    @Override
    protected List crawlPage(int pageNum) throws IOException {
         //通过url获取指定网站接口 进行爬取
        return new ArrayList<>();
    }
    
    @Override
    public void start() {
        try {
            doTask("http://www.huoxing24.com/news");
        } catch (IOException e) {
            log.error("抓取火星网新闻异常", e);
        }
    }
}
 

至于什么时候去爬取资讯,我们可以通过定时器,定时去爬取。

定时任务类

@Slf4j
@Component
public class ScheduleHuoXingTrigger {

    @Autowired
    private CrawlerHuoXingService crawlerHuoXingService;

    
    @Scheduled(initialDelay = 1000, fixedDelay = 15 * 60 * 1000)
    public void doCrawlHuoXing() {
    
        try {
            crawlerHuoXingService.start();
        } catch (Exception e) {
            log.error("本次抓取火星资讯异常", e);
        }
    }
}

整个大致流程就是这样,以后要是添加一条资讯那就只要写多个具体实现类就行

 

转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号