模式导读:
讲真,生活中每一件事似乎做起来都很有"仪式感",无论是吃饭,谈恋爱,学习,还是银行业务办理等等,我们都得按照一定的步骤去执行,中间有些步骤则是需要我们仔细斟酌然后再选择去执行,这便涉及到了模块方法模式,即定义一个操作中的算法骨架,将某些步骤延迟到子类中实现,这样新的子类可以在不改变一个算法结构的前提下重新定义该算法的某些特定步骤。
核心:
处理某个流程的代码都已经具备,但是其中某个节点的代码暂时不能确定,因此我们采用工厂方法模式,将这个节点的代码实现转移给子类完成,即处理步骤父类中定义好,具体实现延迟到子类中定义。
参考类图:
方法回调(钩子方法):
子类不能调用父类,而通过父类调用子类,这些调用步骤已经在父类中写好了,完全由父类控制整个过程。
原理就是实现为空的方法,在某任务之前、之后、执行中、报异常后调用的方法。通常钩子方法是通过抽象类或是本类中的空方法来实现的。
代码实现:
1.定义一个抽象银行业务类,里面涉及到了方法回调方法(钩子方法),将具体业务的实现放到了子类中
1 //银行处理基本业务流程 ->对外提供一套固定的逻辑体系 2 public abstract class AbstractBankService { 3 // 取号业务 4 public void getNum() { 5 System.out.println("-->取号业务完成!"); 6 } 7 8 // 具体业务处理,比如存款,取款,转账等等 9 public abstract void dealWork(); 10 11 // 评价服务 12 public void Componment() { 13 System.out.println("-->对此次服务进行评价"); 14 } 15 16 // 具体的模块执行方法,把基本操作组合到一起,子类一般不能重写 17 public final void process() { 18 this.getNum(); 19 this.dealWork(); 20 this.Componment(); 21 } 22 }
2.具体的业务实现子类,这里我直接在该类中将所有具体业务操作一起实现了(违反了带一职责原则),最好选择分为多个子类去实现特定的业务功能
1 //细节业务实现 2 public class DetailService extends AbstractBankService { 3 // 存款业务 4 public void deposit() { 5 System.out.println("存款业务进行中!"); 6 } 7 8 // 取款业务 9 public void withDraw() { 10 System.out.println("取款业务进行中!"); 11 } 12 13 // 转账业务 14 public void thansfer() { 15 System.out.println("转账业务进行中!"); 16 } 17 18 // 贷款业务 19 public void loan() { 20 System.out.println("贷款业务进行中!"); 21 } 22 23 @Override 24 public void dealWork() { 25 System.out.println("-----存款-----"); 26 deposit(); 27 System.out.println("-----取款-----"); 28 withDraw(); 29 System.out.println("-----转账-----"); 30 thansfer(); 31 System.out.println("-----贷款-----"); 32 loan(); 33 } 34 }
3.客户端类:
1 //客户端 2 public class Client { 3 public static void main(String[] args) { 4 5 AbstractBankService bank = new DetailService(); 6 bank.process(); 7 } 8 }
效果截图:
模块方法模式优缺点:
优点:
1、定义了一组算法,将具体的实现交由子类负责。
2、是一种代码复用的基本技术。
3、导致一种反向的控制结构,通过一个父类调用其子类的操作,通过对子类的扩展增加新的行为,符合“开闭原则”。
缺点:
每一个不同的实现都需要一个子类来实现,导致类的个数增加,使得系统更加庞大。
适用场景:
1.一次性实现一个算法的不变的部分,并将可变的行为留给子类来实现。
2.各子类中公共的行为应被提取出来并集中到一个公共父类中以避免代码重复。
3.控制子类的扩展。