10

谁能告诉我一些应该使用模板方法 - 模式的示例情况?

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

(到目前为止,我发现它仅对 DA 层中的映射数据有用。对不起!!!)

4

9 回答 9

9

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

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

例子:

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

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

于 2009-10-12T11:04:37.017 回答
6

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

  1. 有一个基类(在 Java 中,只有一个带有protected构造函数并且可以选择声明为abstract),它将在客户端代码中被子类化。
  2. 基类中定义了两组方法: a) 一个或多个模板方法(通常只有一个)和一个或多个原始操作方法(通常不止一个)。每个模板方法代表一个高级操作,在基类本身中根据原始操作实现,这些操作旨在在每个特定子类中实现/覆盖。通常,模板方法是公共的且不可覆盖(finalJava 中的 ,​​ );它的 API 文档必须精确地指定它调用了哪些原始操作方法,以及何时调用(也就是说,它必须描述“算法”)。代表算法中的一个步骤的原始操作方法应该是非公开的但可以覆盖(protected, 在 Java 中),并且可以有两种类型: a)必须在子类中实现的抽象方法;b) 具有默认/空实现的方法,可以在子类中被覆盖。

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

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

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

于 2010-02-15T13:35:48.697 回答
4

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

  • 当你希望你的程序是“Open For Extension”和“Closed for Modification”时。这意味着模块的行为可以被扩展,这样我们就可以使模块以新的和不同的方式作为应用程序的要求来运行改变,或者满足新应用的需要。但是,这样的模块的源代码是不可侵犯的。不允许任何人对其源代码进行更改。在下面的例子中,你可以添加新的工资计算方式(如远程上课)而不更改以前的代码。

    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();
        }
    }
    
  • 当您面对许多通过延迟算法的某些步骤而重复的相同代码行时。当您实现方法或函数的内容时,您会发现代码的某些部分因一种类型而异。该部分的特点是可以重新定义或修改方法或函数的这些部分,而无需更改算法(方法或函数)的主要结构。例如,如果您想在不使用此模式的情况下解决此问题,您将面临以下示例:

功能0:功能1:...功能N:

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

如您所见,部分 cods 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
            ...
        }
        ...
    }
    
于 2017-09-10T12:11:40.727 回答
3

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

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

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

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

于 2011-12-13T03:32:25.170 回答
2

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

于 2014-05-12T21:38:05.657 回答
2

我将绘制一个真实世界的示例,其中我使用了一些模板方法。

在 C++ 计算机视觉算法应用程序中,算法的行为被设计为基于在运行时读取的一些选项,根据启动时加载的配置文件中的枚举来假设几种算法行为。该算法的整体框架是相同的,除了一些关键回调塞在中间,否则将是相同的代码部分,只是为了在该级别调用不同的函数而被残酷地复制。我想使用的这些回调被抽象到模板方法基类中,并且模板方法模式防止了所有代码重复。我们使用的枚举基本上决定了我实例化我的基类指针指向的子类,从而使算法在行为上具有相关的味道。

现在,这种运行算法的多样性背后的一些动机是控制我们仪器的软件的在线与离线功能。离线风格带来了更丰富的调试/诊断输出,并保持了一些图像像素的本地坐标系,而在线风格将事物保持在绝对坐标空间中,并保持了特定于正在运行的仪器及其所有机器人的关注点。另一个枚举也推动了我们在用于某些机器学习的一组分类器中进行选择,因为不同的分类器是在不同的数据集下训练的,否则这些数据集以相同的方式流过代码体,但需要根据一些控制条件进行不同的解释该数据已创建。

我相信我的这种用例源于所谓的中间问题。

于 2015-04-30T22:57:49.003 回答
1

我使用了业务逻辑的模板方法,其中许多组件共享相同的流程,但实现略有不同。

于 2009-10-12T11:07:42.207 回答
1

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

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

于 2017-01-17T21:55:41.703 回答
0

本文讨论了模板模式的 6 种常见用法。在 ADO.NET 时代,我经常使用模板模式,因为我们有固定的顺序,如打开、执行查询和关闭连接,但是执行查询会根据不同的表结构有不同的查询.

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

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

  1. 灵活可扩展的通用专用用户界面
  2. ASP.NET 页面生命周期
  3. 代码生成器
  4. XML 解析器
  5. 业务组件中的验证
  6. 可定制的日志记录实用程序
于 2020-06-27T06:42:04.720 回答