我们应该在哪里使用模板方法 - 模式?

时间:2009-10-12 10:40:57

标签: design-patterns template-method-pattern

任何人都可以告诉我一些应该使用模板方法 - 模式的示例情况吗?

根据您自己的经验,给我一些真实的用途。

(到目前为止,我发现它仅适用于在DA层中映射数据。抱歉!!!)

8 个答案:

答案 0 :(得分:8)

模板方法模式提供了执行任何类型的算法或操作的框架,它允许子类重新定义逻辑的一部分。

优点:自然适合构建框架,以便父框架类可以回调到子项中实现的方法。

示例:

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

缺点:将您限制为Java中的单个继承。

答案 1 :(得分:6)

模板方法模式的应用有两个主要特征:

  1. 有一个基类(在Java中,只有一个protected构造函数,可选地声明为abstract),它将在客户端代码中进行子类化。
  2. 基类中定义了两组方法:a)一个或多个模板方法(通常只有一个)和一个或多个原语操作方法(通常不止一个)。每个模板方法表示一个高级操作,在基类操作中根据基本操作实现,这些操作意味着在每个特定子类中实现/覆盖。通常,模板方法是公共的,不可覆盖的(final,在Java中);它的API文档必须精确指定它调用哪些基本操作方法,以及何时(即它必须描述“算法”)。表示算法中的一个步骤的原始操作方法应该是非公共的,但是可以覆盖(Java中为protected),并且可以有两种类型:a)必须的抽象方法em>在子类中实现; b)具有默认/空实现的方法,可以在子类中重写。
  3. Java 6 SDK中的一个很好的例子是execute()类的javax.swing.SwingWorker方法(它是public final void方法)。在这种情况下,基本操作方法是doInBackground()process(List)done()。第一个是抽象的,因此需要在子类中实现;它是由后台线程中的模板方法调用的。其他两个有空实现,可以选择在子类中重写;它们分别在EDT(Swing Event Dispatch Thread)中在处理期间和结束时调用,以允许更新UI。

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

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

答案 2 :(得分:3)

模板方法中最重要的是你必须将一系列抽象方法定义为步骤或算法,并让子类替换这些方法的具体实现。

我申请了其中一个文件生成程序。

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

您可以使用不同的实现,例如PDF生成器csv生成器,这里的值是它们符合算法(生成 - >标题,正文,详细信息)。

答案 3 :(得分:2)

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

给出了一个实时示例的详细说明

答案 4 :(得分:2)

我试图给你一些真实的例子,以及应该使用模板方法模式的一些常见情况。

  • 当你希望你的程序是“Open For Extension”和“Closed for Modification”时。这意味着可以扩展模块的行为,这样我们就可以随着应用程序的需求发生变化,或者为了满足新应用程序的需要,模块会以新的和不同的方式运行。但是,这样一个模块的源代码是不可侵犯的。不允许任何人对它进行源代码更改。例如,您可以添加新的工资计算方式(例如Remotely类),而无需更改以前的代码。

    public abstract class Salary {
    
       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();
    
    }
    
    public class Hourly extends Salary {
    
        @Override
        public void getBaseSalary() {
            System.out.println("Special Task is done.");
        }
    
    }
    
    public class Test {
    
        public static void main(String[] args) {
            Salary salary = ....
            salary.calculate();
        }
    }
    
  • 如果您通过延迟算法的某些步骤来面对许多相同的代码行。当您实现方法或函数的内容时,您可以找到某些部分的内容。代码从一种类型到另一种类型。这一部分的特点是可以重新定义或修改方法或函数的这些部分,而无需更改算法的(方法或函数)主结构。例如,如果您想在没有此模式的情况下解决此问题,您将面对以下示例:

function0:function1:... functionN:

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;
        }
    ...
}
  • 当您作为框架的设计者时,希望您的客户只需使用作为参数传递给框架的任何可执行代码,这些代码可以回调(执行)该参数。给定时间。此执行可能是在同步回调中​​立即执行,也可能在稍后的时间发生,如在异步回调中。让我们考虑其中一个着名的。

    public abstract class HttpServlet extends GenericServlet 
        implements java.io.Serializable  {
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
            ...
        }
    
    protected void service(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException {
            ....
            doGet(req, resp);
            ...
        }
        ...
    }
    }
    
    public class MyServlet extends HttpServlet {
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
    
                //do something
            ...
        }
        ...
    }
    

答案 5 :(得分:1)

我使用了Business Logic的模板方法,其中许多组件共享相同的过程,但实现略有不同。

答案 6 :(得分:1)

  

Template方法定义了算法的骨架结构   将某些步骤和细节推迟到子类。结构和   算法的流程保持静态,但步骤的细节是   推迟到子类。

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

答案 7 :(得分:0)

本文讨论了模板模式的6种常用用法。在ADO.NET时代,我使用模板模式的原因很多,因为我们有固定的序列,如open,executequery和close connection,但是executequery的查询与不同的表格结构。

https://www.codeproject.com/Articles/307452/common-use-of-Template-Design-pattern-Design-pat

以上文章讨论了模板模式的六种常见用法:-

  1. 灵活的可扩展通用专业用户界面
  2. ASP.NET页面生命周期
  3. 代码生成器
  4. XML解析器
  5. 业务组件中的验证
  6. 可自定义的日志记录实用程序