Template 模板方法设计模式(参考《java与设计模式》)

在java的各种个样设计模式中,大部分都通过委派来实现,尽量避免继承,因为继承会破坏封装,及时用继承,也是接口继承,类继承很少见,但是模板方法却是为数不多使用继承类的。

为什么要有模板方法?

顶层设计人员可以更加专注于整体架构的设计,而将具体子类实现交由程序员来完成。子类可以置换掉父类的可变部分,但是子类却不可以改变模板方法的顶层逻辑。

模板方法如何实现?

简单的说就是一个AbstractClass 在一个方法中定义一个业务中各个操作的顺序,然后在操作中声明一些抽象函数,然后子类继承后,实现每个抽象函数。

模板方法与基本方法?

模板方法:

模板方法是定义在抽象类中的,把基本操作方法组合在一起形成一个总算法或者一个总行为的方法,在抽象类中定义,子类直接继承不能修改

基本方法:

可分为三类

抽象方法:子类必须自己实现

具体方法:父类设置为final 子类不得修改

钩子方法:子类可以选择是否扩展

ps:对于是用钩子方法还是用抽象方法,模板方法的设计理念是尽量减少必须由子类置换掉的基本数目。


类图



具体代码

package com.company;

abstract public class AbstractClass {
    public void TemplateMethod(){
        doOperation1();
        doOperation2();
        doOperation3();
    }
    //因为只有子类继承和使用,因此这里使用protected修饰
    protected abstract void doOperation1();
    protected abstract void doOperation2();
    //父类实现的方法是通用的方法,不允许再被修改因此使用final修饰
    protected final void doOperation3(){

    }
}


package com.company;

public class ConcreteClass extends AbstractClass {
    @Override
    protected void doOperation1() {
        System.out.println("doOperation1();");
    }

    @Override
    protected void doOperation2() {
        //子类在重写具体方法时,不能在方法内调用父类已经实现的方法比如doOperation3(),
        //因为写在内部就打破了父类定义的操作顺序了
        System.out.println("doOperation2();");
    }
}


例题

考虑一个计算存款利息的例子。假设系统需要支持两种存款账户,即货币市场账户,和定期存款账户。这两种账户的存款利息是不同的,因此在计算一个存户的存款利息额,必须区分两种不同的账户。

提示:对于本题是可以通过在一个类中的if-else然后来对不同的类型的账户选择不同的利率,但如果有新的账户加入时,就必须修改这个类,这就违背了开放封闭原则,但如果采用模板方法,有新的账户加入时只需继承AbstractClass然后实现对应的抽象方法即可,同时银行计算利息的过程是确定的,只是中间不同环节会有细微的差别。


UML


代码:

package com.company;

abstract public class Account {
    protected String accoutNumber;

    public Account()
    {
        accoutNumber=null;
    }

    public Account(String accountNumber)
    {
        this.accoutNumber=accountNumber;
    }

    public final double calculateInterest(){
        double interestRate=doCalculateInterestRate();
        String accountType=doCalculateAccountType();
        double amount=calculateAmount(accountType,accoutNumber);
        return amount*interestRate;
    }

    abstract protected String doCalculateAccountType();
    abstract protected double doCalculateInterestRate();

    final public double calculateAmount(String accountType,String accountNumber)
    {
        //此处应该根据 账户类型和账号返回该账号对应数据库中的金额,简化程序使用固定值
        return 7243.00D;
    }
}
package com.company;

public class MoneyMarketAccount extends Account {
    @Override
    protected String doCalculateAccountType() {
        return "Money Market";
    }

    @Override
    protected double doCalculateInterestRate() {
        return 0.045;
    }
}
package com.company;

public class CDAccount extends Account {
    @Override
    protected String doCalculateAccountType() {
        return "Certificate of Deposite";
    }

    @Override
    protected double doCalculateInterestRate() {
        return 0.065D;
    }
}
package com.company;

public class Client {
    private static Account acct=null;
    public static void main(String[] args) {
   // write your code here
        acct=new MoneyMarketAccount();
        System.out.println("Interest from Money Market account "+acct.calculateInterest());
        acct=new CDAccount();
        System.out.println("Interest from CD account "+acct.calculateInterest());
    }
}


模板方法在Java中的具体应用

HttpServlet:

Servlet接口含有三个方法


GenericServlet继承Servlet,实现了init,destroy,但是没有实现service。 


HttpServlet继承GenericServlet,任然是抽象类,但是实现了service


子类可以继承HttpServlet然后实现七个do方法来完成不同的操作,因此HttpServlet是模板方法的应用。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值