模板方法模式是一种行为设计模式,它定义了一个操作中的算法骨架,而将一些步骤延迟到子类中实现。模板方法使得子类可以在不改变算法结构的情况下重新定义算法的某些特定步骤。
主要特点:
- 固定流程:模板方法定义了执行某些操作的标准流程,并且这个流程是固定的,不能被改变。
- 可变细节:虽然流程固定,但是其中的具体步骤可以由子类来实现,这样就可以在不改变整体流程的前提下修改某些具体的操作。
- 防止子类篡改:模板方法通常定义为final,以防止子类改变模板方法的定义,确保流程的一致性。
组成部分:
- 抽象类(Abstract Class):负责定义一个或多个模板方法,这些方法给出了一个顶级逻辑框架,而逻辑框架的各个步骤则在具体的子类中实现。
- 具体类(Concrete Classes):实现抽象类中定义的一个或多个抽象方法,完成实际的工作。
- 模板方法(Template Method):在抽象类中定义的一个方法,用来定义一个算法的框架,该方法一般被声明为final,防止子类覆盖。
- 基本方法(Primitive Methods):这些是在模板方法中被调用的方法,它们是一些基本的操作,具体实现由子类提供。
应用场景:
- 当你想要让多个子类共享相同的行为,同时保持这些子类之间的差异时,可以使用模板方法模式。
- 当你有一个多步骤的过程,而这些步骤在不同的子类中有不同的实现时,可以使用模板方法模式。
- 当你希望重构代码以减少代码重复时,可以考虑使用模板方法模式来提取公共行为。
示例:
假设我们正在开发一个咖啡店应用,不同类型的咖啡制作过程大致相同,但是具体的步骤如加糖、加奶等可能会有所不同。这时,我们可以使用模板方法模式来设计程序。
// 抽象类
abstract class Coffee {
// 模板方法,定义制作咖啡的流程
final void makeCoffee() {
boilWater();
brewCoffeeGrinds();
pourInCup();
addCondiments();
}
void boilWater() {
System.out.println("Boiling water");
}
abstract void brewCoffeeGrinds();
void pourInCup() {
System.out.println("Pouring into cup");
}
abstract void addCondiments();
}
// 具体类
class Americano extends Coffee {
@Override
void brewCoffeeGrinds() {
System.out.println("Dripping coffee through filter");
}
@Override
void addCondiments() {
System.out.println("Adding nothing extra");
}
}
class Cappuccino extends Coffee {
@Override
void brewCoffeeGrinds() {
System.out.println("Steaming milk");
}
@Override
void addCondiments() {
System.out.println("Adding frothed milk and cocoa powder");
}
}
在这个例子中,makeCoffee()
方法是一个模板方法,它定义了制作咖啡的基本流程。而 brewCoffeeGrinds()
和 addCondiments()
是需要在子类中实现的基本方法,因为不同的咖啡类型在这两个步骤上的处理方式不同。
面是使用 Python 和 PHP 实现模板方法模式的例子。这两个例子都展示了如何通过模板方法模式来定义一个咖啡制作过程,其中具体的步骤(比如加糖、加奶)由子类来实现。
下面是使用 Python 和 PHP 实现模板方法模式的例子。这两个例子都展示了如何通过模板方法模式来定义一个咖啡制作过程,其中具体的步骤(比如加糖、加奶)由子类来实现。
Python 实现
from abc import ABC, abstractmethod
# 抽象类
class Coffee(ABC):
def make_coffee(self):
self.boil_water()
self.brew_coffee_grinds()
self.pour_in_cup()
self.add_condiments()
def boil_water(self):
print("Boiling water")
@abstractmethod
def brew_coffee_grinds(self):
pass
def pour_in_cup(self):
print("Pouring into cup")
@abstractmethod
def add_condiments(self):
pass
# 具体类
class Americano(Coffee):
def brew_coffee_grinds(self):
print("Dripping coffee through filter")
def add_condiments(self):
print("Adding nothing extra")
class Cappuccino(Coffee):
def brew_coffee_grinds(self):
print("Steaming milk")
def add_condiments(self):
print("Adding frothed milk and cocoa powder")
# 测试代码
americano = Americano()
americano.make_coffee()
print("\n")
cappuccino = Cappuccino()
cappuccino.make_coffee()
PHP 实现
<?php
// 抽象类
abstract class Coffee {
public function makeCoffee() {
$this->boilWater();
$this->brewCoffeeGrinds();
$this->pourInCup();
$this->addCondiments();
}
protected function boilWater() {
echo "Boiling water\n";
}
abstract protected function brewCoffeeGrinds();
protected function pourInCup() {
echo "Pouring into cup\n";
}
abstract protected function addCondiments();
}
// 具体类
class Americano extends Coffee {
protected function brewCoffeeGrinds() {
echo "Dripping coffee through filter\n";
}
protected function addCondiments() {
echo "Adding nothing extra\n";
}
}
class Cappuccino extends Coffee {
protected function brewCoffeeGrinds() {
echo "Steaming milk\n";
}
protected function addCondiments() {
echo "Adding frothed milk and cocoa powder\n";
}
}
// 测试代码
$americano = new Americano();
$americano->makeCoffee();
echo "\n";
$cappuccino = new Cappuccino();
$cappuccino->makeCoffee();
?>
解释
在上述两个示例中,Coffee
类是一个抽象类,它定义了一个模板方法 make_coffee
或 makeCoffee
,以及几个具体的方法和抽象方法。具体的方法如 boil_water
或 boilWater
和 pour_in_cup
或 pourInCup
在抽象类中已经实现了,因为这些步骤对于所有类型的咖啡都是相同的。
抽象方法 brew_coffee_grinds
或 brewCoffeeGrinds
和 add_condiments
或 addCondiments
需要在子类中实现,因为不同的咖啡类型可能有不同的冲泡方式和添加的调料。
Americano
和 Cappuccino
类继承自 Coffee
类并实现了抽象方法,提供了具体的实现细节。
通过这种方式,模板方法模式允许我们在不改变整个流程的前提下,灵活地修改或扩展具体的步骤。