面向对象(下)——模板方法设计模式的应用场景
在多态的典型应用中,模板方法设计模式(Template Method)是一种非常实用的结构。该模式通过抽象类来体现其核心思想:抽象类作为多个子类的通用框架,子类在其基础上进行扩展或定制,但整体行为流程仍由父类控制。
整体步骤很固定、通用,这些步骤已经在父类中写好了。但是某些部分易变,易变部分可以抽象出来,供不同子类实现。
解决的核心问题
- 当某个功能的实现中,部分步骤是固定的,而另一些步骤是可变的,可以将可变的部分延迟到子类中实现。
- 换句话说,在软件开发过程中,若需定义一个算法的基本骨架,而将其中某些具体步骤延迟至子类实现,此时便可使用模板方法模式。
模版模式
模板方法模式示例说明
以 spendTime 方法为例,该方法用于计算某段代码的执行耗时。整个计时过程具有固定流程:获取开始时间 → 执行目标代码 → 获取结束时间 → 输出差值。其中,“执行目标代码”这一环节是不确定的,因此将其声明为抽象方法,交由子类具体实现。
这样一来,开发者只需关注“要运行什么代码”,而不必重复编写计时逻辑。模板负责控制流程,子类负责具体内容。
实际案例:判断质数并统计耗时
例如,我们需要查找 1000 以内所有的质数。判断一个数是否为质数时,只需检查从 2 到 √n 的整数是否存在因子即可。因为如果存在大于 √n 的因子,那么必然对应一个小于 √n 的因子,而我们在较小范围的遍历中已经能够发现。
举例验证:97 是否为质数?
√97 ≈ 9.85,因此只需测试 2 到 9 之间的整数能否整除 97 即可。无需检查 10 及以上数值。假设 97 能被 11 整除(11 > √97),则商约为 8.8,不是整数;而任何大于 √97 的因子所对应的另一个因子必定小于 √97,因此在小范围检测中已能覆盖所有可能情况。
代码实现
public class TemplateTest {
public static void main(String[] args) {
new Template() {
@Override
void code() {
// 查找1000以内所有的质数,只能被1和本身除尽
for (int i = 2; i <= 1000; i++) {
boolean isFlag = true;
// 如果一个数不是质数,它必定能被 ≤√i 的某个整数整除
for (int j = 2; j <= Math.sqrt(i); j++) {
if (i % j == 0) {
isFlag = false;
break; // 发现因子,说明不是质数,立即跳出
}
}
if (isFlag) {
System.out.print(i + "; ");
}
}
}
}.spendTime(); // 获取运行代码的时间
}
}
abstract class Template {
// 运行某段代码花费的时间:整体步骤很固定、通用
void spendTime() {
long start = System.currentTimeMillis(); // 获取运行代码之前的时间
code(); // 运行代码,具体执行内容由子类决定
long end = System.currentTimeMillis();
System.out.println("\n运行代码花费的时间:" + (end - start));
}
abstract void code(); // 抽象方法,留给子类实现具体逻辑
}
上述代码中,Template 类定义了执行时间测量的通用模板,而具体的业务逻辑(如查找质数)则在匿名子类中实现。这种设计既提高了代码复用性,又保持了流程的一致性。
以下是一系列按顺序排列的数值:2; 3; 5; 7; 11; 13; 17; 19; 23; 29; 31; 37; 41; 43; 47; 53; 59; 61; 67; 71; 73; 79; 83; 89; 97; 101; 103; 107; 109; 113; 127; 131; 137; 139; 149; 151; 157; 163; 167; 173; 179; 181; 191; 193; 197; 199; 211; 223; 227; 229; 233; 239; 241; 251; 257; 263; 269; 271; 277; 281; 283; 293; 307; 311; 313; 317; 331; 337; 347; 349; 353; 359; 367; 373; 379; 383; 389; 397; 401; 409; 419; 421; 431; 433; 439; 443; 449; 457; 461; 463; 467; 479; 487; 491; 499; 503; 509; 521; 523; 541; 547; 557; 563; 569; 571; 577; 587; 593; 599; 601; 607; 613; 617; 619; 631; 641; 643; 647; 653; 659; 661; 673; 677; 683; 691; 701; 709; 719; 727; 733; 739; 743; 751; 757; 761; 769; 773; 787; 797; 809; 811; 821; 823; 827; 829; 839; 853; 857; 859; 863; 877; 881; 883; 887; 907; 911; 919; 929; 937; 941; 947; 953; 967; 971; 977; 983; 991; 997;
程序执行所耗费的时间为:17。
整体步骤很固定、通用,这些步骤已经在父类中写好了。但是某些部分易变,易变部分可以抽象出来,供不同子类实现。

雷达卡


京公网安备 11010802022788号







