模版模式
类型
行为型设计模式
核心思想
模板模式的核心思想是“模板方法模式”,即将算法的核心部分抽象出来,以便子类可以在不改变算法整体结构的情况下重新定义某些步骤。
概述
定义了一个算法的骨架,将一些步骤延迟到子类中实现,从而使得子类可以改变算法的某些特定步骤,但算法的流程不变。模板模式通常由一个抽象基类来实现算法的骨架,其中包含了一些抽象方法,这些方法由子类来实现具体的步骤。同时,抽象基类中也可以包含一些具体的方法,这些方法对于所有子类都是通用的。
也就是将所有重复的都上升到父类,子类进行继承,而不是重复实现
场景
当要完成某一个细节层次一致的一个过程或一系列步骤,但其个别步骤在更详细的层次实现可能不同时,通常考虑模版方法模式处理。
结构图
主要角色
- 抽象类(Abstract Class):定义了一个模板方法,该方法中包含了算法的骨架,同时也可以定义一些具体的方法和抽象方法,抽象方法由子类来实现,(在golang中经常抽象类可以使用接口)。
- 具体类(Concrete Class):继承自抽象类,实现抽象方法,从而完成算法的具体步骤。
优缺点
优点
让算法的骨架固定下来,从而可以提高代码的可读性。同时,它也可以保证算法的执行顺序,避免了一些潜在的错误。保证逻辑顺序的可靠性。
并且将不变的行为搬运到父类中,有效去除子类中的重复的代码,提高代码的复用性。
缺点
有时会过度使用继承,从而导致代码的可读性和可维护性降低。此外,如果算法的步骤变化太多,那么它可能会成为一个不适合使用模板模式的场景。
demo(golang)
做饮料:
假设有一个制作饮料的流程,包含以下步骤:选材、加工、调味、装杯。其中,选材和加工是必须的步骤,而调味和装杯是可选的步骤,可以在子类中选择实现或者不实现。 整体流程:
type BeverageMaker interface {
ChooseIngredients()
Process()
AddSeasoning()
PourIntoCup()
}
func makeBeverage(b BeverageMaker) {
b.ChooseIngredients()
b.Process()
if b.hasSeasoning {
b.AddSeasoning()
}
b.PourIntoCup()
}
子类实现:做一杯咖啡
type CoffeeMaker struct {
hasSeasoning bool
}
func (c *CoffeeMaker) ChooseIngredients() {
fmt.Println("Choosing coffee beans and water")
}
func (c *CoffeeMaker) Process() {
fmt.Println("Brewing coffee")
}
func (c *CoffeeMaker) AddSeasoning() {
c.hasSeasoning = true
fmt.Println("Adding sugar and milk")
}
func (c *CoffeeMaker) PourIntoCup() {
fmt.Println("Pouring coffee into cup")
}
实际调用
func main() {
coffeeMaker := &CoffeeMaker{}
makeBeverage(coffeeMaker)
}
总结
模版模式可以帮助我们简化复杂的算法,并提高代码的复用性和可维护性