要理解这两种设计模式首先要知道创建线程的两种方式!
创建线程有两种方式,一种是创建Thread,一种是实现Runnable接口,其实这种说法不严谨。准确的强,创建线程只有一种方式,那就是创建Thread类,而实现线程的执行单元有两种方式,一种是重写Thread类的run方法,另一种是实现runnable接口,并把Runnable实例当做参数传入到Thread构造方法中去。
1.模板设计模式
线程的真正的执行逻辑是在run方法中,通常我们会把run方法称为线程的执行单元,用start方法启动线程
Thread的run和start就是一个比较典型的模板设计模式,父类编写算法结构代码,子类实现逻辑细节
例:
public class Test { public final void print(String message) { System.out.println("################"); wrapPrint(message); System.out.println("################"); } protected void wrapPrint(String message) { } public static void main(String[] args) { Test test = new Test(){ @Override protected void wrapPrint(String message) { System.out.println("自定义逻辑1:"+message); } }; test.print("你好1!"); Test test2 = new Test(){ @Override protected void wrapPrint(String message) { System.out.println("自定义逻辑2:"+message); } }; test2.print("你好2!"); } }
结果:
################
自定义逻辑1:你好1!
################
################
自定义逻辑2:你好2!
################
print(String message)相当于start()方法,wrapPrint(String message)相当于run()方法,这样做的好处就是程序结构由父类控制,并且final修饰,不允许被重写,子类只需要自己的重写逻辑任务即可。
2.策略模式
无论是Runnable的run方法,还是Thread类本身的ran方法(事实上 Thread类也是实现了 Runnable接口)都是想将线程的控制本身和业务逻辑的运行分离开来, 达到职责分明、功能单一的原则,这一点与GoF设计模式中的策略设计模式很相似
例如:
相信很多人都做过关于JDBC的开发,下面我们在这里做一个简单的查询操作,只不 过是把数据的封装部分抽取成一个策略接口
public interface RowHandler
{
T handle(ResultSet rs);
}
RowHandler接口只负责对从数据库中查询出来的结果集进行操作,至于最终返回成 什么样的数据结构,那就需要你自己去实现,类似于Runnable接口
public class RecordQuery {
private final Connection connection;
public RecordQuery(Connection connection)
{
this.connection = connection;
public
{
try (PreparedStatement stmt = connection.prepareStatement(sql))
{
int index = 1;
for (Object param : params)
{
stmt.setObject(index++, param);
ResultSet resultSet = stmt.executeQuery();
return handler.handle(resultSet);//①调用 RowHandler
}
}
}
RecordQuery中的query只负责将数据查询出来,然后调用RowHandler进行数据封装, 至于将其封装成什么数据结构,那就得看你自己怎么处理了,下面我们来看看这样做有什 么好处?上面这段代码的好处是可以用query方法应对任何数据库的査询,返回结果的不同 只会因为你传人RowHandler的不同而不同,同样RecordQuery只负责数据的获取,而 RowHandler则负责数据的加工,职责分明,每个类均功能单一,相信通过这个简单的示例 大家应该能够清楚Thread和Runnable之间的关系了