模板方法是一种行为设计模式,它允许您在基类中定义算法的骨架,并让子类覆盖这些步骤而不改变整体算法的结构。
模板方法是定义算法骨架的默认实现,其他方法可以在具体类型中重新定义。
这里算法整体结构不只是指普通算法,可以指指具有凝聚性的业务逻辑聚合,在领域模型中定义业务逻辑的整体结构,不涉及实现细节,定义这些整体结构中元素之间的关系,类似桥模式中的一种组合方式,也类似组合模式中保护繁杂的树形凝聚结构关系。
模板方法模式在 Python 框架中很常见。开发人员经常使用它为框架用户提供一种使用继承扩展标准功能的简单方法。如果您在基类中看到一个方法调用了一堆其他抽象或空的方法,则可以识别模板方法。
Java中用抽象类实现模板。
Rust中用接口trait实现:
main.rs
trait TemplateMethod { fn template_method(&self) { self.base_operation1(); self.required_operations1(); self.base_operation2(); self.hook1(); self.required_operations2(); self.base_operation3(); self.hook2(); }
fn base_operation1(&self) { println!("TemplateMethod says: I am doing the bulk of the work"); }
fn base_operation2(&self) { println!("TemplateMethod says: But I let subclasses override some operations"); }
fn base_operation3(&self) { println!("TemplateMethod says: But I am doing the bulk of the work anyway"); }
fn hook1(&self) {} fn hook2(&self) {}
fn required_operations1(&self); fn required_operations2(&self); }
struct ConcreteStruct1;
impl TemplateMethod for ConcreteStruct1 { fn required_operations1(&self) { println!("ConcreteStruct1 says: Implemented Operation1") }
fn required_operations2(&self) { println!("ConcreteStruct1 says: Implemented Operation2") } }
struct ConcreteStruct2;
impl TemplateMethod for ConcreteStruct2 { fn required_operations1(&self) { println!("ConcreteStruct2 says: Implemented Operation1") }
fn required_operations2(&self) { println!("ConcreteStruct2 says: Implemented Operation2") } }
fn client_code(concrete: impl TemplateMethod) { concrete.template_method() }
fn main() { println!("同一客户代码可以与不同的具体实现一起工作:"); client_code(ConcreteStruct1); println!();
println!("同一客户代码可以与不同的具体实现一起工作:"); client_code(ConcreteStruct2); }
|
流程模板
如果业务中步骤流程固定,而且这个流程必须固定才符合业务规则,那么可以把流程用模板方法写死:
基类定义一个工作流,派生类将覆盖工作流中的方法。
首先我们定义一个BaseHandler trait来作为基类定义工作流程:然后我们的 "派生 "类UserHandler将通过重写方法:
trait BaseHandler { fn authorized(&self) -> bool { false }
fn get(&self) -> String { if !self.authorized() { return "403 Forbidden".to_string(); } println!("Do some basic work"); // handle rest work to do_get self.do_get() }
fn do_get(&self) -> String; }
struct UserHandler;
impl BaseHandler for UserHandler { fn authorized(&self) -> bool { true }
fn do_get(&self) -> String { "Processed by User handler".to_string() } }
fn main() { let handler = UserHandler {}; println!("{}", handler.get()); }
|
输出:
Do some basic work Processed by User handler
|
开发框架与模板
Spring等Java框架是模板方法的升级,框架和模板化的好处是统一风格,提高团队工作效率,下面是网友经验:
其实我对Go很感兴趣,因为它被设计成一种更有生产力的语言。然而,我注意到,由于没有一个流行的框架,而大多数Go程序员不喜欢使用框架,这将导致一系列较小的设计决定。基本上,通过使用Spring,我得到了跨代码库的统一性,这有助于我提高工作效率。在Go中,似乎要花更多的精力才能获得这种效果。我没有专业地使用Go,只是一些想法。