模板方法设计模式与生活的关系

299 阅读3分钟

摘要:学习的过程是由已知概念去学习未知概念,编程中的很多概念,并不是新的概念,平时生活中都有使用。我们通过生活中的经验和编程类似概念类比思考,来加速我们的学习过程。

本文讨论GOF中最常用的设计模式「模板方法-TemplateMethod」,这个模式不仅仅编程中常用,生活中也是经常会使用的,比如当你申请银行卡或信用卡的时候,就会用到「模板方法」。

模板方法GOF:定义一个操作中的算法骨架,而将一些步骤延迟到子类中。

1. 生活中申请信用卡表格

比如我们申请银行卡的时候,需要填写如下表格,每个人只需要在XXX的地方填写为自己的信息就可以了。

                         信用卡申请表
客户姓名:XXX
身份证号:XXXXXXXXXXXX
本人同意以下授权,实例省略实例省略实例省略实例
省略实例省略实例省略实例省略实例省略。
                                                          申请人签名:XXXX
                                                          申请日期:XXXXX

如果没有这个「文档模板」,我们每个人都重复书写全部的这个申请表,显然是重复的,客户大概率就换家银行办卡了。

「文档模板」其实是每个人申请信用卡的重复文字部分,模板打印出来,每个人只需要申请的时候填写空白部分就可以了。

模板的处理办法,就是共用重复的部分做成模板,每个场景只需要关注变化部分。 下面我们可以看看编程中的「模板方法」模式是否是一样的。

2. 编程中使用模板方法

编程里使用的模板思想和申请银行卡用的模板是完全一样的,目的是为了不重复书写代码。

模板方法.png

  • 填空形式从银行卡申请表变成了抽象类。
  • 申请表的空白填空变成了抽象方法。
  • 填空的过程替换为子类程序继承父类进行实现抽象方法或OverWrite。

3. 代码实例

比如我们互联网架构中,为了提升性能,我们可以使用数据库+缓存提升数据的访问速度。数据库和缓存的数据配合过程在每个模块都是一样的(比如既可用于文章缓存,也可用于缓存用户信息),没必要重复书写。 模板部分:统一定义了算法过程框架(DB和缓存的结合使用过程)

public abstract class DataLoader<T> {
    public abstract T getObjectFromCache(Long id);

    public abstract T getObjectFromDb(Long id);

    public abstract void setObjectToCache(Long id, T Object);

    public T getObject(Long id) {
        //先从cache中取
        T object = this.getObjectFromCache(id);
        if (null != object) {
            //缓存中渠道直接返回
            return object;
        }
        //缓存中取不到,再从db取
        object = this.getObjectFromDb(id);
        //把DB取到的结果放进缓存,此处只是示例,真实线上需要对null进行占位,不然会不存在数据一直击穿到数据库
        if (null != object) {
            this.setObjectToCache(id, object);
        }
        return object;
    }
}

具体填空的子类如下:只需要填空,不需要考虑了解整个过程细节

//dao和cache不应该耦合mysql和redis,此处这样命名为了简化本示例,增加易读性。
DataLoader<Article> dataLoader = new DataLoader<Article>() {
    @Override
    public Article getObjectFromDb(Long id) {
        //从数据库根据ID查询文章
        return articleDaoMysql.getCplArticleById(id);
    }

    @Override
    public Article getObjectFromCache(Long id) {
        //从缓存根据ID查询文章
        return articleCacheRedis.getCplArticleById(id);
    }

    @Override
    public void setObjectToCache(Long id, Article article) {
        //保存文章到Redis缓存中
        articleCacheRedis.cacheArticle(id, article);
    }
};
Long id = 100L;
Article article = dataLoader.getObject(id);