本文是我们名为“ Java设计模式 ”的学院课程的一部分。
在本课程中,您将深入研究大量的设计模式,并了解如何在Java中实现和利用它们。 您将了解模式如此重要的原因,并了解何时以及如何应用模式中的每一个。 在这里查看 !
目录
- 1.简介 2.什么是模板设计模式 3.实施模板设计模式 4.在模板内部引入一个挂钩 5.何时使用模板设计模式 6. JDK中的模板模式 7.下载源代码
1.简介
模板设计模式是一种行为模式,顾名思义,它提供了供用户使用的模板或算法结构。 用户无需改变算法的结构即可提供自己的实现。
在问题的帮助下更容易理解这种模式。 我们将在本节中了解场景,并在下一节中使用Template模式实施解决方案。
您是否曾经使用Java应用程序连接到关系数据库? 让我们回想一下连接数据并将数据插入数据库所需的一些重要步骤。 首先,根据要连接的数据库,需要一个驱动程序。 然后,我们将一些凭据传递给数据库,然后,准备一条语句,将数据设置到insert语句中,然后使用insert命令将其插入。 稍后,我们关闭所有连接,并有选择地销毁所有连接对象。
无论任何供应商的关系数据库,您都需要编写所有这些步骤。 考虑一个问题,您需要将一些数据插入不同的数据库。 您需要从CSV文件中获取一些数据,然后将其插入MySQL数据库中。 一些数据来自文本文件,应将其插入Oracle数据库中。 唯一的区别是驱动程序和数据,其余步骤应该相同,因为JDBC提供了一组通用的接口来与任何供应商的特定关系数据库进行通信。
我们可以创建一个模板,该模板将为客户端执行一些步骤,并留下一些步骤让客户端以自己的特定方式实现它们。 (可选)客户端可以覆盖某些已定义步骤的默认行为。
现在,在实现代码之前,让我们进一步了解模板设计模式。
2.什么是模板设计模式
模板模式定义了操作中算法的框架,将某些步骤推迟到子类。 模板方法允许子类在不更改算法结构的情况下重新定义算法的某些步骤。
模板方法模式可以在存在算法的情况下使用,其中某些步骤可以以多种不同方式实现。 在这种情况下,模板方法模式建议将算法的大纲保留在一个类(称为模板类)内的称为模板方法的单独方法中,而忽略变体部分的具体实现(步骤该算法可以针对此类的不同子类以多种不同方式实现)。
Template类不一定必须将实现全部留给子类。 而是,作为提供算法概述的一部分,Template类还可以提供一定数量的实现,这些实现可以视为在不同实现之间是不变的。 如果合适,它甚至可以为变体部件提供默认实现。 在不同的子类中将仅实现特定的细节。 这种实现方式消除了对重复代码的需求,这意味着要编写的代码量最少。
抽象类
- 定义具体的子类定义的抽象基本操作,以实现算法的步骤。
- 实现定义算法框架的模板方法。 模板方法调用原始操作以及在
AbstractClass
定义的操作或其他对象的操作。
ConcreteClass
- 实现原始操作进行。
3.实施模板设计模式
在下面,我们可以看到连接模板类,该类用于为客户端提供一个用于连接各种数据库并与之通信的模板。
package com.javacodegeeks.patterns.templatepattern;public abstract class ConnectionTemplate {public final void run() {setDBDriver();setCredentials();connect();prepareStatement();setData();insert();close();destroy();}public abstract void setDBDriver();public abstract void setCredentials();public void connect() {System.out.println("Setting connection...");}public void prepareStatement() {System.out.println("Preparing insert statement...");}public abstract void setData();public void insert() {System.out.println("Inserting data...");}public void close() {System.out.println("Closing connections...");}public void destroy() {System.out.println("Destroying connection objects...");}
}
抽象类提供了连接,通信以及稍后关闭连接的步骤。 必须完成所有这些步骤才能完成工作。 该类为某些常见步骤提供了默认实现,并将特定步骤保留为抽象,从而迫使客户端为其提供实现。
用户应该实现setDBDriver
方法以提供特定于数据库的驱动程序。 对于不同的数据库,凭据可能不同; 因此, setCredentials
也保留为抽象状态,以使用户可以实现它。
同样,使用JDBC API连接到数据库并准备语句是很常见的。 但是,数据将是特定的,因此用户将提供它,而其他步骤(如运行插入语句,关闭连接和销毁对象)则与任何数据库相似,因此它们的实现在模板内保持通用。
上一类的关键方法是run
方法。 run
方法用于按顺序运行这些步骤。 该方法被设置为最终方法,因为这些步骤应保持安全,并且任何用户都不得更改。
下面的两个类扩展了模板类,并为某些方法提供了特定的实现。
package com.javacodegeeks.patterns.templatepattern;public class MySqLCSVCon extends ConnectionTemplate {@Overridepublic void setDBDriver() {System.out.println("Setting MySQL DB drivers...");}@Overridepublic void setCredentials() {System.out.println("Setting credentials for MySQL DB...");}@Overridepublic void setData() {System.out.println("Setting up data from csv file....");}
}
上面的类用于连接到MySQL数据库,并通过读取CSV文件提供数据。
package com.javacodegeeks.patterns.templatepattern;public class OracleTxtCon extends ConnectionTemplate {@Overridepublic void setDBDriver() {System.out.println("Setting Oracle DB drivers...");}@Overridepublic void setCredentials() {System.out.println("Setting credentials for Oracle DB...");}@Overridepublic void setData() {System.out.println("Setting up data from txt file....");}
}
上面的类用于连接到Oracle数据库,并通过读取文本文件来提供数据。
现在,让我们测试代码。
package com.javacodegeeks.patterns.templatepattern;public class TestTemplatePattern {public static void main(String[] args) {System.out.println("For MYSQL....");ConnectionTemplate template = new MySqLCSVCon();template.run();System.out.println("For Oracle...");template = new OracleTxtCon();template.run();}
}
上面的代码将导致以下输出:
For MYSQL....
Setting MySQL DB drivers...
Setting credentials for MySQL DB...
Setting connection...
Preparing insert statement...
Setting up data from csv file....
Inserting data...
Closing connections...
Destroying connection objects... For Oracle...
Setting Oracle DB drivers...
Setting credentials for Oracle DB...
Setting connection...
Preparing insert statement...
Setting up data from txt file....
Inserting data...
Closing connections...
Destroying connection objects...
上面的输出清楚地显示了模板模式如何使用类似的方式与不同的数据库连接和通信。 该模式将通用代码保留在一个类下,并提高了代码的可重用性。 它为用户设置了一个框架并对其进行控制,并允许用户扩展模板,以便为某些步骤提供特定的实现。
现在,如果我们通过添加日志记录机制来增强上述示例。 但是代码的某些用户不想添加此功能,要实现此功能,我们可以使用钩子。 挂钩是模板类内部具有默认行为的简单方法; 此行为可用于更改一些可选步骤。 用户应实现此方法,该方法可以挂接到模板类内部以更改算法的可选步骤。
4.在模板内部引入一个挂钩
让我们用钩子增强上面的示例。
package com.javacodegeeks.patterns.templatepattern;import java.util.Date;public abstract class ConnectionTemplate {private boolean isLoggingEnable = true;public ConnectionTemplate() {isLoggingEnable = disableLogging();}public final void run() {setDBDriver();logging("Drivers set [" + new Date() + "]");setCredentials();logging("Credentails set [" + new Date() + "]");connect();logging("Conencted");prepareStatement();logging("Statement prepared [" + new Date() + "]");setData();logging("Data set [" + new Date() + "]");insert();logging("Inserted [" + new Date() + "]");close();logging("Conenctions closed [" + new Date() + "]");destroy();logging("Object destoryed [" + new Date() + "]");}public abstract void setDBDriver();public abstract void setCredentials();public void connect() {System.out.println("Setting connection...");}public void prepareStatement() {System.out.println("Preparing insert statement...");}public abstract void setData();public void insert() {System.out.println("Inserting data...");}public void close() {System.out.println("Closing connections...");}public void destroy() {System.out.println("Destroying connection objects...");}public boolean disableLogging() {return true;}private void logging(String msg) {if (isLoggingEnable) {System.out.println("Logging....: " + msg);}}
}
我们在上述模板类中引入了两个新方法。 disableLogging
是一个返回boolean
的钩子。 默认情况下,启用日志记录的布尔值isLoggingEnable
为true。 如果应该为他的代码禁用日志记录,则用户可以覆盖此方法。 另一种是用于记录消息的私有方法。
下面的类实现了hook方法并返回false,从而关闭了此特定工作的日志记录机制。
package com.javacodegeeks.patterns.templatepattern;public class MySqLCSVCon extends ConnectionTemplate {@Overridepublic void setDBDriver() {System.out.println("Setting MySQL DB drivers...");}@Overridepublic void setCredentials() {System.out.println("Setting credentials for MySQL DB...");}@Overridepublic void setData() {System.out.println("Setting up data from csv file....");}@Overridepublic boolean disableLogging() {return false;}
}
让我们测试一下这段代码。
package com.javacodegeeks.patterns.templatepattern;public class TestTemplatePattern {public static void main(String[] args) {System.out.println("For MYSQL....");ConnectionTemplate template = new MySqLCSVCon();template.run();System.out.println("For Oracle...");template = new OracleTxtCon();template.run();}
}
上面的类将导致以下输出:
For MYSQL....
Setting MySQL DB drivers...
Setting credentials for MySQL DB...
Setting connection...
Preparing insert statement...
Setting up data from csv file....
Inserting data...
Closing connections...
Destroying connection objects... For Oracle...
Setting Oracle DB drivers...
Logging....: Drivers set [Sat Nov 08 23:53:47 IST 2014]
Setting credentials for Oracle DB...
Logging....: Credentails set [Sat Nov 08 23:53:47 IST 2014]
Setting connection...
Logging....: Conencted
Preparing insert statement...
Logging....: Statement prepared [Sat Nov 08 23:53:47 IST 2014]
Setting up data from txt file....
Logging....: Data set [Sat Nov 08 23:53:47 IST 2014]
Inserting data...
Logging....: Inserted [Sat Nov 08 23:53:47 IST 2014]
Closing connections...
Logging....: Conenctions closed [Sat Nov 08 23:53:47 IST 2014]
Destroying connection objects...
Logging....: Object destoryed [Sat Nov 08 23:53:47 IST 2014]
您可以在输出中清楚地看到,对于MySQL实现,日志记录已关闭,而对于Oracle实现,日志记录已关闭。
5.何时使用模板设计模式
在以下情况下应使用模板方法模式:
- 一次实现算法的不变部分,然后将其留给子类来实现可以变化的行为。
- 子类之间的共同行为应分解并集中在一个共同类中,以避免代码重复。 您首先要确定现有代码中的差异,然后将差异分为新的操作。 最后,将不同的代码替换为调用这些新操作之一的模板方法。
- 控制子类扩展。 您可以定义一个模板方法,该方法在特定点调用“挂钩”操作(请参阅结果),从而仅允许在这些点进行扩展。
6. JDK中的模板模式
-
java.util.Collections#sort()
-
java.io.InputStream#skip()
-
java.io.InputStream#read()
-
java.util.AbstractList#indexOf()
7.下载源代码
这是有关模板设计模式的课程。 您可以在此处下载源代码: TemplatePattern-Project
翻译自: https://www.javacodegeeks.com/2015/09/template-design-pattern.html