2009-10-12 74 views

回答

1

我想给你一些真实世界的例子,并且应当使用模板方法模式的常见情况。

  • 当你想你的程序是“对扩展开放”,也是‘对修改关闭’。这意味着模块的行为可以扩展,使得我们能够在新的模块的行为以及根据应用程序需求的变化或满足新应用程序需求的不同方式,但这种模块的源代码是不可侵犯的,任何人都不得对源代码进行修改,在下面的例子中,您可以在不改变以前的代码添加工资计算(如远程类)的新方式。

    公共抽象类薪水{

    public final void calculate() { 
        System.out.println("First shared tasks is done."); 
        getBaseSalary(); 
        System.out.println("Second shared tasks is done."); 
    } 
    
    public abstract void getBaseSalary(); 
    

    }

    公共类每小时薪水扩展{

    @Override 
    public void getBaseSalary() { 
        System.out.println("Special Task is done."); 
    } 
    

    }

    公共类的测试{

    public static void main(String[] args) { 
        Salary salary = .... 
        salary.calculate(); 
    } 
    

    }

  • 当你面对的是通过推迟只是你的算法的一些步骤重复代码的许多同一直线上。当你正在实现一个方法或函数的内容时,你可以找到你的代码的一部分,从一个类型到另一个类型。本节的特点是可以在不改变算法(方法或函数)主要结构的情况下重新定义或修改方法或函数的这些部分。例如,如果你想解决这个问题,而这个模式,你会面临这样的例子:

function0:功能1:...功能N:

1  1    1 
2  2    2 
...  ...    ... 
5  6    n 
3  3    3 
4  4    4 
...  ...    ... 

正如你所看到的,部分鳕5, 6,n是不同的从一个功能到另一个功能,但是你有共享部分,如1,2,3,4是重复的。让我们考虑一个着名的java库的解决方案。

public abstract class InputStream implements Closeable { 

    public abstract int read() throws IOException; 

    public int read(byte b[], int off, int len) throws IOException { 
     .... 

     int c = read(); 
     .... 
    } 

    .... 

} 

public class ByteArrayInputStream extends InputStream { 

    ... 

    public synchronized int read() { 
     return (pos < count) ? (buf[pos++] & 0xff) : -1; 
     } 
    ... 
} 
  • 当你作为一个框架的设计者,想你的客户只需为使用作为参数传递给你的框架,预计回调(执行)的任何可执行代码在特定时间的论点。这种执行可能会像在同步回调中​​那样立即执行,或者可能会在以后发生,就像在异步回调中一样。让我们考虑一个着名的。

    公共抽象类HttpServlet的扩展GenericServlet类 实现java.io.Serializable { 保护无效的doGet(HttpServletRequest的REQ,HttpServletResponse的RESP){ ... }

    protected void service(HttpServletRequest req, HttpServletResponse resp) 
        throws ServletException, IOException { 
         .... 
         doGet(req, resp); 
         ... 
        } 
        ... 
    } 
    

    }

    公共类MyServlet扩展HttpServlet {

    protected void doGet(HttpServletRequest request, HttpServletResponse response) 
        throws ServletException, IOException { 
    
         //do something 
        ... 
    } 
    ... 
    

    }

7

模板方法图案提供一种用于执行任何种类的算法或操作的骨架,和它允许子类重新定义部分逻辑。

优点:天生适合构建框架,以便父框架类可以对子节点中实现的方法进行回调。

例子:

  • java.util.AbstractList
  • servlet的doGet和doPost方法
  • MDB的onMessage方法
  • Struts Action类
  • Spring的数据访问类

缺点:限制你到一个单一的我Java中的继承。

+0

我只看了一下AbstractList和HttpServlet类。我没有看到任何“模板方法”。我怀疑你用简单的“控制反转”用法混淆了模板方法模式。这个模式不是关于一个基类的方法被框架调用,而是有一个方法来封装一个算法,该算法可以被覆盖特殊扩展点的子类自定义(从模板方法调用的基类的可重写方法,本身并不意味着被覆盖)。 – 2010-02-14 16:00:16

+0

@Rogerio *你*看不到这个模式并不意味着'HttpServlet'和'AbstractList'不是很好的例子。通过'HttpServelt',子类**可以实现'doGet','doPost'等等,这些是'service'中调用的扩展点(这是容器为每个请求按容器调用的唯一方法)。使用'AbstractList',子类**可以执行'get','size','set','remove'(只需查看javadoc标题),它们是扩展点。我没有看到提到的扩展点的任何IoC。 – 2010-02-14 21:07:44

+0

@Rogerio所以,我不是教我什么Ioc和模板模式,而是先学会认识他们(如果你认为我以前错了,要求*你的真相)。也可以学习servlet如何工作。但不要责怪我*你的*无知。因此,我不谢谢你们不相干的倒行逆施,我请你们重新考虑。 – 2010-02-14 21:10:21

1

我已经使用了业务逻辑模板方法,其中一些组件共享相同的进程,但实现稍有不同。

6

模板方法图案的应用有两个主要特点:

  1. 有一个基类(在Java中,一个只与protected构造函数和任选声明为abstract),这将在客户端被继承码。
  2. 2基团的方法在基类中定义:a)一种或多种模板方法(通常仅一个)和一个或多个原语操作方法(通常超过一个)。每个模板方法代表一个高级操作,在基类自身中根据基本操作实现,这些操作意味着在每个特定的子类中被实现/覆盖。通常,模板方法是公开的且不可覆盖的(在Java中为final);其API文档必须精确指定它调用的原始操作方法,以及何时(即它必须描述“算法”)。表示算法中的一个步骤的原始操作方法应该是非公开的但可以重写的(用Java编码的protected),并且可以有两种类型:a)在子类中实现的抽象方法必须; b)具有默认/空实现的方法,其中可能在子类中被覆盖。在Java 6 SDK

一个很好的例子是javax.swing.SwingWorker类(它是一个public final void方法)的方法​​。在这种情况下,原始操作方法是doInBackground()process(List)done()。第一个是抽象的,因此需要在子类中实现;它在后台线程中由模板方法调用。另外两个具有空的实现,可以在子类中被重写;它们分别在EDT(Swing Event Dispatch Thread)中处理期间和处理结束时被调用,以允许更新UI。

在我自己的经验,我有时用这个模式。 一种这样的情况下是一个Java基类实现java.util.Iterator接口,其中next()是模板的方法和只有一个负责实例特定域实体类原语操作的方法(这是指迭代的持久性的列表时使用的域实体对象,使用JDBC)。 在同一个应用程序中的一个更好的例子是一个基类,其中模板方法实现了一个多步算法,旨在从给定的持久实体列表中填充“业务实体维护屏幕”(使用Swing);原始操作方法被调用以1)清除当前屏幕状态,以及2)在屏幕内的表视图中添加实体;可选地,如果屏幕是可编辑的,则从模板方法调用其他基本操作。

最后,我必须说,虽然这肯定是一个有益的设计模式,不是经常的情况出现在那里真的是适用的。简单地拥有一个基类,其中包含在子类中被覆盖的方法(根据我的经验,这是一种更为常见的情况),本身并不足以作为该模式的应用。

3

模板方法中最重要的事情是,你必须定义一系列的抽象方法的步骤或算法,让子类替代与这些方法的具体实施。

我在一个文件生成程序中应用。

public abstract DocumentGenerator() 
{ 
    generateHeader(); 
    generateBody(); 
    generateDetails(); 
} 
public HTMLDocGenerator : DocumentGenerator() 
{ 
    public override generateBody() 
    { 
    //generate as in html format 
    } 
} 

你可以有不同的实现,如PDF生成CSV发生器和这里的价值是他们comform的算法(生成 - >标题,正文,细节)。

2

当存在具有许多实现的算法时,应该使用模板模式。该算法在基类中的函数中定义,实现由基类和子类完成。具有实时例子详细说明在http://preciselyconcise.com/design_patterns/templatemethod.php

+0

>>“当存在具有许多实现的算法时,应使用模板模式。”不,这是一个错误。 你所描述的是*战略*模式。模板方法模式是关于让子类替换算法中的某些步骤。 – 2017-11-26 16:53:39

2

给出我会草拟一个现实世界的例子,我使用了一些模板的方法。

在C++计算机视觉算法应用程序中,算法的行为被设计为基于在运行时根据枚举入启动时加载的配置文件中的枚举的某些选项假设一些算法行为的风格。算法的整体框架除了一些关键回调之外是完全相同的,否则这些回调会成为相同的代码段,为了调用该级别的不同功能,这些代码将被残酷地复制。我想要使​​用的这些回调被抽象到模板方法基类中,并且模板方法模式阻止了所有代码重复。我们使用的枚举基本上决定了我实例化我的基类指针所指向的子类,从而借助该算法将其行为中的相关位置赋予其相关位。

现在一些背后各种运行算法的口味的动机之一是在线VS软件的离线功能,控制我们的仪器。离线风格随其更丰富的调试/诊断输出而被保留,并且对于某些图像像素保持局部坐标系统,而在线风味将事物保持在绝对坐标空间中,并且保持关于具有其所有机器人的运行仪器的特定关注点以及哪些不是。另一个枚举驱动我们用于某些机器学习的一组分类器之间的选择,因为不同的分类器是在不同的数据集之下进行训练的,否则这些数据集通过代码体相同地流动,但需要根据一些控制条件该数据已创建。

我相信这种使用情况下,我从什么被称为hole in the middle问题出现了。

1

Template方法定义算法的骨架结构,但 将某些步骤和细节推迟到子类。结构和算法的 流量保持不变,但这些步骤的细节 推迟到子类。

我用模板方法模式编写文档内容。有许多不同类型的文档,每种类型都有自己的小修改。然而,文件编制的主要过程对所有人来说都是一样的。

相关问题