二、☆模板方法模式(TEMPLATE METHOD)
定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。TemplateMethod使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
– 《设计模式:可复用面向对象软件的基础》
结合上一节的例子:
由LifecycleBase定义了一个算法骨架,来实现Lifecycle接口的init()方法。这个算法骨架就是模板方法。
LifecycleBase类是一个通用的类,所以其中的逻辑只能是通用的逻辑。这些逻辑写在init()方法中,即通过setStateInternal方法触发相应状态的事件等功能逻辑。
调用一个抽象方法initInternal(),这个方法交由子类去重写,来实现具体业务逻辑。
1. 总结一下模板方法模式适用的场景:
- 一个算法逻辑由多个类实现,不同的类之间的逻辑有通用的也有个性化的。
- 创建一个抽象类,完成算法骨架。
- 抽象类中实现通用逻辑,并调用一个空方法,具体逻辑交由子类实现。
- 继承抽象类的子类实现自身的个性化逻辑。
2. 模板方法模式的好处:
- 代码复用,子类不用再写一遍通用的逻辑。
- 定义了算法骨架,对算法实现进行了约束。
- 权限隔离,抽象类和子类可能由不同角色完成,子类的修改不会影响通用逻辑,也就不会影响其他子类。
类图如下:
(图二)(引自《设计模式:可复用面向对象软件的基础》)
这也是非常惯例的一种实现方式,如果一个接口会被多个不同类实现,那么常见的操作就是使用一个类去实现这个接口,在这个实现类中编写通用的方法,并调用需要子类实现的抽象方法。子类直接或间接继承这个抽象类,并根据自身需要实现具体逻辑。
三、所有核心组件的Init方法传递
继续上一篇的Catalina类的load()方法,此时完成了对Server.xml文件的解析,并将其赋值给了Catalina的server属性。接下来就是调用getServer().init();方法进行初始化。Server组件作为最上层组件,我们已经知道了其初始化是如何进行的,那么其他子组件是如何统一 管理的呢?
看一下第一节中StandardServer类的initInternal()方法的代码,在最后一部分通过循环遍历的方式调用了所有Service的init方法。
// 初始化定义的 Services for (Service service : services) { service.init(); }
同理,由图一可知,Service同样是继承了LifecycleBase类,所以Service和Server的上层通用逻辑是一样的,那么看一下StandardService的initInternal()方法:
@Override protected void initInternal() throws LifecycleException { super.initInternal(); //Engine 初始化 if (engine != null) { engine.init(); } // 初始化 Executors for (Executor executor : findExecutors()) { if (executor instanceof JmxEnabled) { ((JmxEnabled) executor).setDomain(getDomain()); } executor.init(); } // 初始化 mapper listener mapperListener.init(); // 初始化 our defined Connectors synchronized (connectorsLock) { for (Connector connector : connectors) { connector.init(); } } }
其中进行了Engine、Executors、mapperListener、Connectors的初始化,以此类推,其他的组件的initInternal()方法我们就不逐一研究了,因为此处暂不关心这几个组件的功能,仅关注组件之间的关系和调用逻辑。具体每个组件的功能及处理逻辑在单独学习该组件的时候再进行分析。
大概流程如下(只画了部分组件):
(图三)