阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

模板方法

277次阅读
没有评论

共计 2855 个字符,预计需要花费 8 分钟才能阅读完成。

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

模板方法(Template Method)是一个比较简单的模式。它的主要思想是,定义一个操作的一系列步骤,对于某些暂时确定不下来的步骤,就留给子类去实现好了,这样不同的子类就可以定义出不同的步骤。

因此,模板方法的核心在于定义一个“骨架”。我们还是举例说明。

假设我们开发了一个从数据库读取设置的类:

public class Setting {public final String getSetting(String key) {String value = readFromDatabase(key);
        return value;
    }

	private String readFromDatabase(String key) {// TODO: 从数据库读取
    }
}

由于从数据库读取数据较慢,我们可以考虑把读取的设置缓存起来,这样下一次读取同样的 key 就不必再访问数据库了。但是怎么实现缓存,暂时没想好,但不妨碍我们先写出使用缓存的代码:

public class Setting {public final String getSetting(String key) {// 先从缓存读取:
        String value = lookupCache(key);
        if (value == null) {// 在缓存中未找到, 从数据库读取:
            value = readFromDatabase(key);
            System.out.println("[DEBUG] load from db:" + key + "=" + value);
            // 放入缓存:
            putIntoCache(key, value);
        } else {System.out.println("[DEBUG] load from cache:" + key + "=" + value);
        }
        return value;
    }
}

整个流程没有问题,但是,lookupCache(key)putIntoCache(key, value) 这两个方法还根本没实现,怎么编译通过?这个不要紧,我们声明抽象方法就可以:

public abstract class AbstractSetting {public final String getSetting(String key) {String value = lookupCache(key);
        if (value == null) {value = readFromDatabase(key);
            putIntoCache(key, value);
        }
        return value;
    }

    protected abstract String lookupCache(String key);

    protected abstract void putIntoCache(String key, String value);
}

因为声明了抽象方法,自然整个类也必须是抽象类。如何实现 lookupCache(key)putIntoCache(key, value)这两个方法就交给子类了。子类其实并不关心核心代码 getSetting(key) 的逻辑,它只需要关心如何完成两个小小的子任务就可以了。

假设我们希望用一个 Map 做缓存,那么可以写一个LocalSetting

public class LocalSetting extends AbstractSetting {private Map<String, String> cache = new HashMap<>();

    protected String lookupCache(String key) {return cache.get(key);
    }

    protected void putIntoCache(String key, String value) {cache.put(key, value);
    }
}

如果我们要使用 Redis 做缓存,那么可以再写一个RedisSetting

public class RedisSetting extends AbstractSetting {private RedisClient client = RedisClient.create("redis://localhost:6379");

    protected String lookupCache(String key) {try (StatefulRedisConnection<String, String> connection = client.connect()) {RedisCommands<String, String> commands = connection.sync();
            return commands.get(key);
        }
    }

    protected void putIntoCache(String key, String value) {try (StatefulRedisConnection<String, String> connection = client.connect()) {RedisCommands<String, String> commands = connection.sync();
            commands.set(key, value);
        }
    }
}

客户端代码使用本地缓存的代码这么写:

AbstractSetting setting1 = new LocalSetting();
System.out.println("test =" + setting1.getSetting("test"));
System.out.println("test =" + setting1.getSetting("test"));

要改成 Redis 缓存,只需要把 LocalSetting 替换为RedisSetting

AbstractSetting setting2 = new RedisSetting();
System.out.println("autosave =" + setting2.getSetting("autosave"));
System.out.println("autosave =" + setting2.getSetting("autosave"));

可见,模板方法的核心思想是:父类定义骨架,子类实现某些细节。

为了防止子类重写父类的骨架方法,可以在父类中对骨架方法使用final。对于需要子类实现的抽象方法,一般声明为protected,使得这些方法对外部客户端不可见。

Java 标准库也有很多模板方法的应用。在集合类中,AbstractListAbstractQueuedSynchronizer 都定义了很多通用操作,子类只需要实现某些必要方法。

练习

使用模板方法增加一个使用 Guava Cache 的子类。

下载练习

思考:能否将 readFromDatabase() 作为模板方法,使得子类可以选择从数据库读取还是从文件读取。

再思考如果既可以扩展缓存,又可以扩展底层存储,会不会出现子类数量爆炸的情况?如何解决?

小结

模板方法是一种高层定义骨架,底层实现细节的设计模式,适用于流程固定,但某些步骤不确定或可替换的情况。

正文完
星哥玩云-微信公众号
post-qrcode
 0
星锅
版权声明:本站原创文章,由 星锅 于2024-08-05发表,共计2855字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
阿里云-最新活动爆款每日限量供应
评论(没有评论)
验证码
【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中

星哥玩云

星哥玩云
星哥玩云
分享互联网知识
用户数
4
文章数
19348
评论数
4
阅读量
7815572
文章搜索
热门文章
开发者必备神器:阿里云 Qoder CLI 全面解析与上手指南

开发者必备神器:阿里云 Qoder CLI 全面解析与上手指南

开发者必备神器:阿里云 Qoder CLI 全面解析与上手指南 大家好,我是星哥。之前介绍了腾讯云的 Code...
星哥带你玩飞牛NAS-6:抖音视频同步工具,视频下载自动下载保存

星哥带你玩飞牛NAS-6:抖音视频同步工具,视频下载自动下载保存

星哥带你玩飞牛 NAS-6:抖音视频同步工具,视频下载自动下载保存 前言 各位玩 NAS 的朋友好,我是星哥!...
云服务器部署服务器面板1Panel:小白轻松构建Web服务与面板加固指南

云服务器部署服务器面板1Panel:小白轻松构建Web服务与面板加固指南

云服务器部署服务器面板 1Panel:小白轻松构建 Web 服务与面板加固指南 哈喽,我是星哥,经常有人问我不...
我把用了20年的360安全卫士卸载了

我把用了20年的360安全卫士卸载了

我把用了 20 年的 360 安全卫士卸载了 是的,正如标题你看到的。 原因 偷摸安装自家的软件 莫名其妙安装...
星哥带你玩飞牛NAS-3:安装飞牛NAS后的很有必要的操作

星哥带你玩飞牛NAS-3:安装飞牛NAS后的很有必要的操作

星哥带你玩飞牛 NAS-3:安装飞牛 NAS 后的很有必要的操作 前言 如果你已经有了飞牛 NAS 系统,之前...
阿里云CDN
阿里云CDN-提高用户访问的响应速度和成功率
随机文章
240 元左右!五盘位 NAS主机,7 代U硬解4K稳如狗,拓展性碾压同价位

240 元左右!五盘位 NAS主机,7 代U硬解4K稳如狗,拓展性碾压同价位

  240 元左右!五盘位 NAS 主机,7 代 U 硬解 4K 稳如狗,拓展性碾压同价位 在 NA...
终于收到了以女儿为原型打印的3D玩偶了

终于收到了以女儿为原型打印的3D玩偶了

终于收到了以女儿为原型打印的 3D 玩偶了 前些日子参加某网站活动,获得一次实物 3D 打印的机会,于是从众多...
开源神器组合!1Panel面板+Halo助你轻松打造个人/企业内容中心

开源神器组合!1Panel面板+Halo助你轻松打造个人/企业内容中心

开源神器组合!1Panel 面板 +Halo 助你轻松打造个人 / 企业内容中心 前言 大家好,我是星哥,之前...
把小米云笔记搬回家:飞牛 NAS 一键部署,小米云笔记自动同步到本地

把小米云笔记搬回家:飞牛 NAS 一键部署,小米云笔记自动同步到本地

把小米云笔记搬回家:飞牛 NAS 一键部署,小米云笔记自动同步到本地 大家好,我是星哥,今天教大家在飞牛 NA...
亚马逊云崩完,微软云崩!当全球第二大云“摔了一跤”:Azure 宕机背后的配置风险与警示

亚马逊云崩完,微软云崩!当全球第二大云“摔了一跤”:Azure 宕机背后的配置风险与警示

亚马逊云崩完,微软云崩!当全球第二大云“摔了一跤”:Azure 宕机背后的配置风险与警示 首先来回顾一下 10...

免费图片视频管理工具让灵感库告别混乱

一言一句话
-「
手气不错
开发者福利:免费 .frii.site 子域名,一分钟申请即用

开发者福利:免费 .frii.site 子域名,一分钟申请即用

  开发者福利:免费 .frii.site 子域名,一分钟申请即用 前言 在学习 Web 开发、部署...
12.2K Star 爆火!开源免费的 FileConverter:右键一键搞定音视频 / 图片 / 文档转换,告别多工具切换

12.2K Star 爆火!开源免费的 FileConverter:右键一键搞定音视频 / 图片 / 文档转换,告别多工具切换

12.2K Star 爆火!开源免费的 FileConverter:右键一键搞定音视频 / 图片 / 文档转换...
星哥带你玩飞牛 NAS-10:备份微信聊天记录、数据到你的NAS中!

星哥带你玩飞牛 NAS-10:备份微信聊天记录、数据到你的NAS中!

星哥带你玩飞牛 NAS-10:备份微信聊天记录、数据到你的 NAS 中! 大家对「数据安全感」的需求越来越高 ...
浏览器自动化工具!开源 AI 浏览器助手让你效率翻倍

浏览器自动化工具!开源 AI 浏览器助手让你效率翻倍

浏览器自动化工具!开源 AI 浏览器助手让你效率翻倍 前言 在 AI 自动化快速发展的当下,浏览器早已不再只是...
多服务器管理神器 Nexterm 横空出世!NAS/Win/Linux 通吃,SSH/VNC/RDP 一站式搞定

多服务器管理神器 Nexterm 横空出世!NAS/Win/Linux 通吃,SSH/VNC/RDP 一站式搞定

多服务器管理神器 Nexterm 横空出世!NAS/Win/Linux 通吃,SSH/VNC/RDP 一站式搞...