use*_*312 8 design-patterns template-method-pattern
任何人都可以让我知道应该使用模板方法 - 模式的一些示例情况吗?
根据您自己的经验,给我一些真实的用途.
(到目前为止,我发现它仅用于映射DA层中的数据.抱歉!!!)
甲模板方法图案提供了一种用于执行任何排序算法或操作的骨架,并且它允许所述子类的逻辑的重新定义的一部分.
优点:自然适合构建框架,因此父框架类可以回调到子实现的方法.
例子:
缺点:在Java中将您限制为单个继承.
模板方法模式的应用有两个主要特征:
protected构造函数,可选地声明为abstract),它将在客户端代码中进行子类化.final在Java中); 它的API文档必须精确指定它调用哪些基本操作方法,以及何时(即它必须描述"算法").表示算法中的一个步骤的原始操作方法应该是非公共的,但是可以覆盖(protected在Java中),并且可以是两种类型:a)必须在子类中实现的抽象方法; b)具有默认/空实现的方法,可以在子类中重写.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)在屏幕内的表视图中添加实体; 可选地,如果屏幕是可编辑的,则从模板方法调用其他基本操作.
最后,我必须说,虽然这肯定是一种有用的设计模式,但并不是经常会出现真正适用的情况.简单地让一个基类具有在子类中被覆盖的方法(根据我的经验,更常见的情况)本身并不足以作为模式的应用程序.
我试图为您提供一些现实世界的示例,以及一些应使用模板方法模式的常见情况。
\n\n当你希望你的程序是“Open For Extension\xe2\x80\x9d 并且\xe2\x80\x9cClosed for Modification\xe2\x80\x9d”时。这意味着模块的行为可以扩展,这样我们就可以随着应用程序需求的变化,或者为了满足新应用程序的需要,模块会以新的和不同的方式表现出来。但是,这样的模块的源代码是不可侵犯的。任何人都不允许对其源代码进行更改。下面的示例中,您可以添加新的工资计算方式(例如Remotely class),而无需更改之前的代码。
\n\npublic abstract class Salary {\n\n public final void calculate() {\n System.out.println("First shared tasks is done.");\n getBaseSalary();\n System.out.println("Second shared tasks is done.");\n }\n\n public abstract void getBaseSalary();\n\n}\n\npublic class Hourly extends Salary {\n\n @Override\n public void getBaseSalary() {\n System.out.println("Special Task is done.");\n }\n\n}\n\npublic class Test {\n\n public static void main(String[] args) {\n Salary salary = ....\n salary.calculate();\n }\n}\nRun Code Online (Sandbox Code Playgroud)当您面对许多相同的代码行时,这些代码通过延迟算法的某些步骤而重复。当您实现方法或函数的内容时,您会发现代码的某些部分因一种类型而异。这些部分的特点是可以重新定义或修改方法或函数的这些部分,而不改变算法(方法或函数)的主要结构。例如,如果您想在没有此模式的情况下解决此问题,您将面临以下示例:
函数 0: 函数 1: ... 函数 N:
\n\n1 1 1\n2 2 2\n... ... ...\n5 6 n\n3 3 3\n4 4 4\n... ... ...\nRun Code Online (Sandbox Code Playgroud)\n\n正如您所看到的,第 5、6、n 节的代码在一个函数和另一个函数之间是不同的,但是您共享了重复的节,例如 1、2、3、4。让我们考虑使用著名的 java 库之一的解决方案。
\n\npublic abstract class InputStream implements Closeable {\n\n public abstract int read() throws IOException;\n\n public int read(byte b[], int off, int len) throws IOException {\n ....\n\n int c = read();\n ....\n }\n\n ....\n\n}\n\npublic class ByteArrayInputStream extends InputStream { \n\n ...\n\n public synchronized int read() {\n return (pos < count) ? (buf[pos++] & 0xff) : -1;\n }\n ...\n}\nRun Code Online (Sandbox Code Playgroud)\n\n当您作为框架的设计者时,希望您的客户端仅使用作为参数传递给框架的任何可执行代码,框架预计会在给定时间回调(执行)该参数。此执行可能是立即执行(如在同步回调中),也可能稍后发生(如在异步回调中)。让我们考虑一下著名的之一。
\n\npublic abstract class HttpServlet extends GenericServlet \n implements java.io.Serializable {\n protected void doGet(HttpServletRequest req, HttpServletResponse resp) {\n ...\n }\n\nprotected void service(HttpServletRequest req, HttpServletResponse resp)\n throws ServletException, IOException {\n ....\n doGet(req, resp);\n ...\n }\n ...\n}\n}\n\npublic class MyServlet extends HttpServlet {\n\n protected void doGet(HttpServletRequest request, HttpServletResponse response)\n throws ServletException, IOException {\n\n //do something\n ...\n }\n ...\n}\nRun Code Online (Sandbox Code Playgroud)