Java设计模式--模板方法模式【Template Pattern】

          模板方法模式是类的行为模式,意图是 定义一个操作中算法的框架,而将一些步骤延迟到子类中,使得子类可以不改变算法的结构即可重定义该算法中的某些特定步骤。模板模式的关键是:子类可以置换掉父类的可变部分,但是子类却不可以改变模板方法所代表的顶级逻辑。

       定义一个抽象类,将部分逻辑以具体方法以及具体构造函数的形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑。不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑有不同的实现。这就是模板方法模式的用意。

     模版方法模式由一个抽象类和一个(或一组)实现类通过继承结构组成,抽象类中的方法分为三种:

  • 抽象方法:父类中只声明但不加以实现,而是定义好规范,然后由它的子类去实现。
  • 模版方法:由抽象类声明并加以实现。一般来说,模版方法调用抽象方法来完成主要的逻辑功能,是把基本操作方法组合在一起形成一个总算法或一个总行为的方法,并且,模版方法大多会定义为final类型,指明主要的逻辑功能在子类中不能被重写。
  • 钩子方法:由抽象类声明并加以实现。但是子类可以去扩展,子类可以通过扩展钩子方法来影响模版方法的逻辑。

        抽象类的任务是搭建逻辑的框架,通常由经验丰富的人员编写,因为抽象类的好坏直接决定了程序是否稳定性。

        实现类用来实现细节。抽象类中的模版方法正是通过实现类扩展的方法来完成业务逻辑。只要实现类中的扩展方法通过了单元测试,在模版方法正确的前提下,整体功能一般不会出现大的错误。

        最近在整理各资产的收益报告,各类资产包括股票、债券、基金、期货、期权等,所有资产的收益计算逻辑都一致,都是当日净值/昨日净值-1,只是在获取净值时,不同的净值获取的逻辑有所区别。要用模板方法模式实现该逻辑,归纳起来,这个系统的总行为应当是计算收益率,这也就决定了作为一个模板方法模式的顶级逻辑。由于计算涉及到两个步骤:一个基本方法获取资产类别,另一个基本方法是获取资产净值。这两个基本方法构成具体逻辑,因为资产的类型不同,所以具体逻辑会有所不同。代码如下:

抽象模板角色类

package com.pattern.template;

import java.util.Calendar;
import java.util.Date;
/**
 * 抽象类--资产收益率
 * @author
 *
 */
public abstract class AssetReturnRate {
   public abstract String getAssetType();//获取资产类别
   public abstract Double getAssetValue(Date date,String type);//获取资产净值
   
   public final Double calculateReturnRate(){//计算收益率:final修饰是为了让子类不该写此方法的实现逻辑
	   Double rate=0.0;
	   Calendar cal=Calendar.getInstance();
	   Date today=cal.getTime();
	   cal.add(Calendar.DATE,-1);
	   Date yesterday=cal.getTime();
	   String type=this.getAssetType();
	   Double todayValue=this.getAssetValue(today,type);
	   Double yesterdayValue=this.getAssetValue(yesterday,type);
	   rate=todayValue/yesterdayValue-1;
	   System.out.println("asset's assetReturnRate is "+rate);
	   System.out.println("------------------------------------------------- ");
	   return rate;
   }
}
具体模板角色类,这里分别以股票和债券为例:

package com.pattern.template;

import java.util.Date;
/**
 * 股票收益率
 * @author 
 *
 */
public class StockReturnRate extends AssetReturnRate{

	@Override
	public String getAssetType() {
		System.out.println("asset type is stock....");
		return "Stock";
	}

	@Override
	public Double getAssetValue(Date date,String type) {
		/**
		 * 根据资产类获取净值
		 */
		if(date.getDay()<new Date().getDay()){
			System.out.println("stock's yestoday value is 2000000.00");
			return 2000000.00;
		}
		System.out.println("stock's today value is 10000000.00");
		return 10000000.00;
	}
}
package com.pattern.template;

import java.util.Date;
/**
 * 债券收益率
 * @author
 *
 */
public class BondReturnRate extends AssetReturnRate{

	@Override
	public String getAssetType() {
		System.out.println("asset type is bond....");
		return "bond";
	}

	@Override
	public Double getAssetValue(Date date, String type) {
		/**
		 * 根据资产类获取净值
		 */
		if(date.getDay()<new Date().getDay()){
			System.out.println("bond's yestoday value is 1000000.00");
			return 1000000.00;
		}
		System.out.println("bond's today value is 1500000.00");
		return 1500000.00;
	}

}
客户端类

package com.pattern.template;

public class Client {
    public static void main(String[] args){
    	AssetReturnRate a1=new StockReturnRate();
    	a1.calculateReturnRate();//股票收益率计算
    	AssetReturnRate a2=new BondReturnRate();
    	a2.calculateReturnRate();//债券收益率计算
    }
}
测试结果:


模版方法的优缺点及适用场景

优点:

       容易扩展:一般来说,抽象类中的模版方法是不易反生改变的部分,而抽象方法是容易反生变化的部分,因此通过增加实现类一般可以很容易实现功能的扩展,符合开闭原则。

       便于维护:对于模版方法模式来说,正是由于他们的主要逻辑相同,才使用了模版方法,假如不使用模版方法,任由这些相同的代码散乱的分布在不同的类中,维护起来是非常不方便的。

       比较灵活:因为有钩子方法,因此,子类的实现也可以影响父类中主逻辑的运行。但是,在灵活的同时,由于子类影响到了父类,违反了里氏替换原则,也会给程序带来风险。这就对抽象类的设计有了更高的要求。

缺点:

      每个不同的实现都需要定义一个子类,这会导致类的个数的增加,设计更加抽象。

适用场景:

       在多个子类拥有相同的方法,并且这些方法逻辑相同时,可以考虑使用模版方法模式。在程序的主框架相同,细节不同的场合下,也比较适合使用这种模式。



源码下载:http://download.csdn.net/download/pelifymeng2/9994744


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值