一、模板方法模式介绍
1. 解决的问题
主要解决在多个子类中重复写某个通用方法的问题。
2. 定义
模板方法模式是一种行为设计模式,它在超类中定义了一个算法的框架,允许子类在不修改结构的情况下重写算法的特定步骤。
3. 应用场景
- 当只希望客户端扩展某个特定算法步骤,而不是整个算法或其结构时,可使用模板方法模式。
- 当多个类的算法除一些细微不同之外几乎完全一样时,可使用模板方法模式。但后果是:只要算法发生变化,可能要修改所有的类。
二、模板方法模式优缺点
1. 优点
- 可以仅允许客户端重写一个大型算法中的特定部分,使得算法的其他部分修改对其所造成的影响减小。
- 可以将重复代码提取到一个超类中。
2. 缺点
- 部分客户端可能会受到算法框架的限制。
- 通过子类抑制默认步骤实现可能会导致违反里氏替换原则。
- 模板方法中的步骤越多,其维护工作就可能越困难。
三、模板方法模式应用实例:开发必备利器 uTools
1. 实例场景
一般来说,开发在学习和工作中都会有各种各样的小工具需求,比如 json 转换、翻译、时间转换、命令文档。
今天就给大家介绍一个私藏多年、可以将上述工具都集合在一起的大利器:uTools。
uTools 是一个极简、插件化的现代桌面软件,通过自由选配丰富的插件,打造得心应手的工具集合。
我最最最常用的就是聚合翻译了,毕竟变量命名是个大问题。
uTools 的翻译功能聚合了有道翻译、谷歌翻译、腾讯翻译,也可以切换选择更多如搜狗翻译、微软翻译等等。
今天,就以 uTools 的聚合翻译插件为例,介绍一下模板方法模式。
2. 状态模式实现
2.1 工程结构
template-pattern
└─ src
├─ main
│ └─ java
│ └─ org.design.pattern.template
│ └─ service
│ ├─ TranslateService.java
│ └─ impl
│ ├─ BaiDuTranslateServiceImpl.java
│ ├─ GoogleTranslateServiceImpl.java
│ └─ YouDaoTranslateServiceImpl.java
└─ test
└─ java
└─ org.design.pattern.template.test
└─ TranslateTest.java
2.2 代码实现
翻译服务超类
/**
* 翻译服务
*/
public abstract class TranslateService {
/**
* 抓取翻译页面
*/
public abstract void crawlTranslatePage();
/**
* 渲染翻译页面iframe
*/
public abstract void renderTranslateIframe();
/**
* 提供翻译
*/
public void provideTranslate() {
crawlTranslatePage();
renderTranslateIframe();
}
}
百度翻译服务实现类
/**
* 百度翻译服务实现类
*/
@Slf4j
public class BaiDuTranslateServiceImpl extends TranslateService {
/**
* 抓取翻译页面
*/
@Override
public void crawlTranslatePage() {
log.info("抓取百度翻译页面");
}
/**
* 渲染翻译页面iframe
*/
@Override
public void renderTranslateIframe() {
log.info("适配并渲染百度翻译页面");
}
}
谷歌翻译服务实现类
/**
* 谷歌翻译服务实现类
*/
@Slf4j
public class GoogleTranslateServiceImpl extends TranslateService {
/**
* 抓取翻译页面
*/
@Override
public void crawlTranslatePage() {
log.info("抓取谷歌翻译页面");
}
/**
* 渲染翻译页面iframe
*/
@Override
public void renderTranslateIframe() {
log.info("适配并渲染谷歌翻译页面");
}
}
有道翻译服务实现类
/**
* 有道翻译服务实现类
*/
@Slf4j
public class YouDaoTranslateServiceImpl extends TranslateService {
/**
* 抓取翻译页面
*/
@Override
public void crawlTranslatePage() {
log.info("抓取有道翻译页面");
}
/**
* 渲染翻译页面iframe
*/
@Override
public void renderTranslateIframe() {
log.info("适配并渲染有道翻译页面");
}
}
2.3 测试验证
2.3.1 测试验证类
/**
* 翻译测试类
*/
public class TranslateTest {
@Test
public void test() {
// 百度翻译
TranslateService baiduTranslate = new BaiDuTranslateServiceImpl();
baiduTranslate.provideTranslate();
// 谷歌翻译
TranslateService googleTranslate = new GoogleTranslateServiceImpl();
googleTranslate.provideTranslate();
// 有道翻译
TranslateService youDaoTranslate = new YouDaoTranslateServiceImpl();
youDaoTranslate.provideTranslate();
}
}
2.3.2 测试结果
16:02:33.610 [main] INFO o.d.p.t.s.i.BaiDuTranslateServiceImpl - 抓取百度翻译页面
16:02:33.612 [main] INFO o.d.p.t.s.i.BaiDuTranslateServiceImpl - 适配并渲染百度翻译页面
16:02:33.612 [main] INFO o.d.p.t.s.i.GoogleTranslateServiceImpl - 抓取谷歌翻译页面
16:02:33.612 [main] INFO o.d.p.t.s.i.GoogleTranslateServiceImpl - 适配并渲染谷歌翻译页面
16:02:33.612 [main] INFO o.d.p.t.s.i.YouDaoTranslateServiceImpl - 抓取有道翻译页面
16:02:33.613 [main] INFO o.d.p.t.s.i.YouDaoTranslateServiceImpl - 适配并渲染有道翻译页面
Process finished with exit code 0
四、模板方法模式结构
- 抽象类(Abstract Class)会声明作为算法步骤的方体,以及依次调用它们的实际模板方法。算法步骤可以被声明为抽象类型,也可以提供一些默认实现。
- 具体类(Concrete Class)可以重写所有步骤,但不能重写模板方法自身。
设计模式并不难学,其本身就是多年经验提炼出的开发指导思想,关键在于多加练习,带着使用设计模式的思想去优化代码,就能构建出更合理的代码。
源码地址:https://github.com/yiyufxst/design-pattern-java
参考资料:
小博哥重学设计模式:https://github.com/fuzhengwei/itstack-demo-design
深入设计模式:https://refactoringguru.cn/design-patterns/catalog