重学设计模式(三设计模式-模板方法模式)

Posted 穆瑾轩

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了重学设计模式(三设计模式-模板方法模式)相关的知识,希望对你有一定的参考价值。

1、模板方法模式

    接下来学习的设计模式都是行为模式,它用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责的分配。

    注:算法是已经定义好的计算程序,将数据或者数据集作为输入,将产生的数据或者数据集操作输出。简单的说,算法是一个过程,一个有输入和输出的指令序列。

    行为型模式分为类行为模式和对象行为模式,前者采用继承机制来在类间分派行为,后者采用组合或聚合在对象间分配行为。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象行为模式比类行为模式具有更大的灵活性。

    在面向对象程序设计过程中,我们往往会遇到这种情况,我们在实现一个算法时,整体的流程是明确的,也有很多步骤是相似的,但是某些步骤的实现可能与具体的情形相关。

    比如:我们去银行办理业务一般要经过这样几个流程:1)取号;2)排队等待叫号;3)办理业务;4)客户评价。其中步骤1、2、4步骤是一致的,可以在父类中实现,只有办理具体的业务因人而异,可能是取现、转账、理财等等,可以延迟到子类中实现。这就是我们今天要学习的模板方法模式。

1.1、什么是模板方法模式

  • 定义

    模板方法一种行为设计模式,它在超类中定义算法的骨架,而将算法的一些步骤延迟到子类中实现,让子类在不改变其结构的情况下覆盖算法的特定步骤。

模板方法的结构:模板方法模式包含以下主要角色

    1)抽象类/抽象模板:负责给出一个算法的骨架,由一个模板方法和若干基本方法构成。

    模板方法:定义了算法的骨架,按某种顺序调用其包含的基本方法;

    基本方法:抽象方法(由子类实现)、具体方法(子类可继承或重写)、钩子方法(或称之为回调,大多数时候,子类调用超类的方法,在模板模式中,由超类模板方法调用子类的方法,完全由父类控制,这就是所谓的好莱坞原则,Don't call me,we' ll call you back;)

    2)具体子类/实现

    实现抽象类中所定义的抽象方法和钩子方法,它们是一个顶级逻辑的一个组成步骤。

    模板方法的意图在于:一个方法里实现一个算法,并推迟定义算法中的某些步骤,从而让其他类重新定义他们。

1.2、模板方法模式的优缺点

  • 优点

    1)它封装了不变部分,扩展可变部分。它把认为是不变部分的算法封装到父类中实现,而把可变部分算法由子类继承实现,便于子类继续扩展。

    2)可以将重复的代码提取到超类中,便于代码复用。

    3)部分方法是由子类实现的,因此子类可以通过扩展方式增加相应的功能,符合开闭原则。

  • 缺点

    1)对每个不同的实现都需要定义一个子类,这会导致类的个数增加,系统更加庞大,设计也更加抽象,间接地增加了系统实现的复杂度。

    2)客户端可能会受到所提供的算法框架的限制,通过子类抑制默认步骤实现违反了里斯替换原则。

1.3、创建方式

1)抽象类/抽象模板

public abstract class BankTemplateAbstract 

	public void takeNumber()
		System.out.println("取号排队");
	
	
	public void WaitingForCall()
		System.out.println("等待叫号");
	
	
	public abstract void transact(); //办理具体的业务
	
	public void evaluate()
		System.out.println("客户评价");
	
	
	//模板方法:实现一个算法,如果不希望子类覆盖它,应该将其设为final
	public void process()
		this.takeNumber();
		this.WaitingForCall();
		this.transact();
		this.evaluate();
	

2)具体子类/实现

//取钱业务
public class DrawMoney extends BankTemplateAbstract

	@Override
	public void transact() 
		System.out.println("取钱");
	


//转账业务
public class TransferAccounts extends BankTemplateAbstract

	@Override
	public void transact() 
		System.out.println("转账");
	

3)客户端

public class Client 

	public static void main(String[] args) 
        //多态的应用
		BankTemplateAbstract drawMoney = new DrawMoney();
		drawMoney.process(); //调用取钱业务
		BankTemplateAbstract transAcc = new TransferAccounts();
		transAcc.process(); //调用转账业务
	

此时的UML关系:

1.4、总结及建议

    模板方法的使用非常频繁,各个框架、类库都有它的影子。我们在分析目标算法的时候,看看是否可以将其分解为步骤,考虑哪些步骤对所有子类是通用的,哪些步骤是易变的,将其抽象出来,供子类实现。

应用场景:

   1)如果想让客户端仅扩展算法的特定步骤而不是整个算法或其结构时,请使用模板方法模式;

   2)当多个子类存在几乎相同的算法但有一些细微差别时,请使用模板方法模式;

   3)当需要控制子类的扩展时,模板方法只在特定点调用钩子操作,这样就只允许在这些点进行扩展。

JDK中模板方法的应用:

   java.util.AbstractList、java.util.AbstractSet、java.util.AbstractMap的所有非抽象方法

   javax.servlet.http.HttpServlet中doGet/doPost方法

以上是关于重学设计模式(三设计模式-模板方法模式)的主要内容,如果未能解决你的问题,请参考以下文章

重学设计模式(三设计模式-解释器模式)

重学设计模式(三设计模式-状态模式)

重学设计模式(三设计模式-状态模式)

重学设计模式(三设计模式-命令模式)

重学设计模式(三设计模式-迭代器模式)

重学设计模式(三设计模式-迭代器模式)