Java设计模式(三)模板方法模式

模板方法:在抽象类中定义了一个模板方法,在模板方法中使用了一些该抽象类中定义的空方法,而这些空方法可以供子类实现。

我们在查看源码时经常能够看到在执行一些重要的方法时,往往调用了一些看似没有什么意义的空方法。其实这就是模板方法。
uml图如下所示

在这里插入图片描述

根据uml举个例子

abstract class ThreadHolder {

    /**
     * 模版方法
     * @param runnable
     */
    public final void run(Runnable runnable) {
        Objects.requireNonNull(runnable, "runnable required not null");
        beforeRun();
        runnable.run();
        afterRun();
    }

    /**
     * 在线程执行之前执行
     */
    protected void beforeRun() {
    }

    /**
     * 在线程执行完之后执行
     */
    protected void afterRun() {
    }
}

在抽象类ThreadHolder中我们定义了beforeRunafterRun两个空方法,供子类实现。然后在模版方法run,我们在线程执行开始和结束分别调用beforeRunafterRun。我们不关心beforeRunafterRun做了什么,供子类按需实现。

然后定义一个实现类。

/**
 * 子类,实现ThreadHolder的空方法
 */
class SimpleThread extends ThreadHolder {

    @Override
    protected void beforeRun() {
        System.out.println("执行之前。。。");
    }

    @Override
    protected void afterRun() {
        System.out.println("执行之后。。。");
    }
}

进行测试


public class AppTest {
    public static void main(String[] args) {
        SimpleThread simpleThread = new SimpleThread();
        simpleThread.run(() -> {
            int n = 10;
            for (int i = 0; i < n; i++) {
                System.out.println("current num is :" + i);
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
    }
}

输出结果:

执行之前。。。
current num is :0
current num is :1
current num is :2
current num is :3
current num is :4
current num is :5
current num is :6
current num is :7
current num is :8
current num is :9
执行之后。。。

其实模版方法被大量使用在各种源码中,通过使用者实现所需的方法,来达到某些监控/日志等目的。

比如在线程池ThreadPoolExecutor中执行任务的方法

	//模版方法
   final void runWorker(Worker w) {
        Thread wt = Thread.currentThread();
        Runnable task = w.firstTask;
        w.firstTask = null;
        w.unlock(); // allow interrupts
        boolean completedAbruptly = true;
        try {
            while (task != null || (task = getTask()) != null) {
                w.lock();
                if ((runStateAtLeast(ctl.get(), STOP) ||
                     (Thread.interrupted() &&
                      runStateAtLeast(ctl.get(), STOP))) &&
                    !wt.isInterrupted())
                    wt.interrupt();
                try {
                	//执行之前
                    beforeExecute(wt, task);
                    Throwable thrown = null;
                    try {
                        task.run();
                    } catch (RuntimeException x) {
                        thrown = x; throw x;
                    } catch (Error x) {
                        thrown = x; throw x;
                    } catch (Throwable x) {
                        thrown = x; throw new Error(x);
                    } finally {
                    	//执行结束
                        afterExecute(task, thrown);
                    }
                } finally {
                    task = null;
                    w.completedTasks++;
                    w.unlock();
                }
            }
            completedAbruptly = false;
        } finally {
            processWorkerExit(w, completedAbruptly);
        }
    }

在执行任务之前之后调用了beforeExecuteafterExecute方法,源码中两个方法都是空的,供子类实现

    protected void beforeExecute(Thread t, Runnable r) { }
    
    protected void afterExecute(Runnable r, Throwable t) { }

所以在我们使用线程池时,如果需要在任务执行之前或者之后做一些监控/日志/计时等操作,通过继承ThreadPoolExecutor类来重写beforeExecuteafterExecute方法实现。

在底层代码,即ThreadHolder中我们就制定了空方法执行顺序,在高层重写空的方法,然后在执行时我们实现的方法就会被底层调用。

展开阅读全文
©️2020 CSDN 皮肤主题: 像素格子 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值