设计模式-模板方法模式详解(2)

模板方法模式详解

目录


1. 模板方法模式简介

1.1 定义

模板方法模式(Template Method Pattern)是一种行为型设计模式,它定义了一个算法的骨架,将一些步骤延迟到子类中实现。模板方法使得子类可以不改变算法的结构,就可以重定义算法的某些特定步骤。

1.2 核心思想

  • 算法骨架固定:定义算法的主要流程,不允许子类改变
  • 步骤可定制:将算法中的某些步骤抽象出来,由子类实现
  • 代码复用:避免重复代码,提高代码复用性
  • 扩展性:通过子类扩展新的实现方式

1.3 适用场景

  • 多个类有相同的算法结构,但具体实现不同
  • 需要控制子类扩展的范围
  • 需要提取公共行为到父类中
  • 框架设计中的钩子方法(Hook Method)

1.4 模板方法模式结构

类图结构
«abstract»
AbstractClass
+templateMethod()
+primitiveOperation1()
+primitiveOperation2()
+concreteOperation()
+hook()
ConcreteClassA
+primitiveOperation1()
+primitiveOperation2()
+hook()
ConcreteClassB
+primitiveOperation1()
+primitiveOperation2()
+hook()
核心组件
  1. AbstractClass(抽象类):定义模板方法和抽象方法
  2. ConcreteClass(具体类):实现抽象方法
  3. Template Method(模板方法):定义算法骨架
  4. Primitive Operations(原语操作):抽象方法,由子类实现
  5. Hook Methods(钩子方法):可选方法,子类可以重写

1.5 模板方法模式分类

基本模板方法模式
// 抽象类定义模板方法
public abstract class AbstractClass {
    // 模板方法,定义算法骨架
    public final void templateMethod() {
        primitiveOperation1();
        primitiveOperation2();
        concreteOperation();
        if (hook()) {
            hookOperation();
        }
    }
  
    // 抽象方法,由子类实现
    protected abstract void primitiveOperation1();
    protected abstract void primitiveOperation2();
  
    // 具体方法,在抽象类中实现
    protected void concreteOperation() {
        System.out.println("具体操作");
    }
  
    // 钩子方法,子类可以重写
    protected boolean hook() {
        return true;
    }
  
    protected void hookOperation() {
        System.out.println("钩子操作");
    }
}
带钩子的模板方法模式
// 带钩子方法的模板方法
public abstract class AbstractClassWithHooks {
    public final void templateMethod() {
        beforeOperation();
        doOperation();
        afterOperation();
        if (needAdditionalOperation()) {
            additionalOperation();
        }
    }
  
    protected abstract void doOperation();
  
    // 钩子方法
    protected void beforeOperation() {
        // 默认空实现
    }
  
    protected void afterOperation() {
        // 默认空实现
    }
  
    protected boolean needAdditionalOperation() {
        return false;
    }
  
    protected void additionalOperation() {
        // 默认空实现
    }
}

2. 核心流程

2.1 模板方法执行流程

客户端 抽象类 具体类 调用templateMethod() 执行primitiveOperation1() 调用子类实现 返回结果 执行primitiveOperation2() 调用子类实现 返回结果 执行concreteOperation() 检查hook()条件 执行hookOperation() alt [hook()返回tru- e] 返回最终结果 客户端 抽象类 具体类

2.2 模板方法设计流程

步骤1:识别算法结构
// 识别需要模板化的算法
public class AlgorithmExample {
    public void processData() {
        // 步骤1:初始化
        initialize();
      
        // 步骤2:验证数据
        validateData();
      
        // 步骤3:处理数据
        processData();
      
        // 步骤4:保存结果
        saveResult();
      
        // 步骤5:清理资源
        cleanup();
    }
  
    private void initialize() { /* 具体实现 */ }
    private void validateData() { /* 具体实现 */ }
    private void processData() { /* 具体实现 */ }
    private void saveResult() { /* 具体实现 */ }
    private void cleanup() { /* 具体实现 */ }
}
步骤2:提取抽象类
// 提取抽象类,定义模板方法
public abstract class DataProcessor {
    // 模板方法,定义算法骨架
    public final void processData() {
        initialize();
        validateData();
        doProcessData();
        saveResult();
        cleanup();
    }
  
    // 具体方法,所有子类共享
    protected void initialize() {
        System.out.println("初始化数据处理器");
    }
  
    protected void validateData() {
        System.out.println("验证数据格式");
    }
  
    protected void saveResult() {
        System.out.println("保存处理结果");
    }
  
    protected void cleanup() {
        System.out.println("清理资源");
    }
  
    // 抽象方法,由子类实现
    protected abstract void doProcessData();
}
步骤3:实现具体类
// 实现具体的数据处理器
public class XmlDataProcessor extends DataProcessor {
    @Override
    protected void doProcessData() {
        System.out.println("处理XML数据");
    }
}

public class JsonDataProcessor extends DataProcessor {
    @Override
    protected void doProcessData() {
        System.out.println("处理JSON数据");
    }
}

public class CsvDataProcessor extends DataProcessor {
    @Override
    protected void doProcessData() {
        System.out.println("处理CSV数据");
    }
}
步骤4:客户端调用
// 客户端使用模板方法
public class Client {
    public static void main(String[] args) {
        DataProcessor xmlProcessor = new XmlDataProcessor();
        xmlProcessor.processData();
      
        DataProcessor jsonProcessor = new JsonDataProcessor();
        jsonProcessor.processData();
      
        DataProcessor csvProcessor = new CsvDataProcessor();
        csvProcessor.processData();
    }
}

2.3 钩子方法使用流程

返回true
返回false
开始模板方法
执行固定步骤1
执行固定步骤2
检查钩子方法
执行钩子操作
跳过钩子操作
执行固定步骤3
结束
钩子方法示例
// 带钩子方法的抽象类
public abstract class AbstractProcessor {
    public final void process() {
        beforeProcess();
        doProcess();
        afterProcess();
      
        // 钩子方法:是否需要额外处理
        if (needAdditionalProcess()) {
            additionalProcess();
        }
      
        // 钩子方法:是否需要日志记录
        if (needLogging()) {
            logProcess();
        }
    }
  
    protected abstract void doProcess();
  
    // 钩子方法,子类可以重写
    protected void beforeProcess() {
        System.out.println("默认前置处理");
    }
  
    protected void afterProcess() {
        System.out.println("默认后置处理");
    }
  
    protected boolean needAdditionalProcess() {
        return false;
    }
  
    protected void additionalProcess() {
        System.out.println("默认额外处理");
    }
  
    protected boolean needLogging() {
        return true;
    }
  
    protected void logProcess() {
        System.out.println("记录处理日志");
    }
}

3. 重难点分析

3.1 重难点一:模板方法的设计原则

难点分析
  • 算法稳定性:模板方法定义的算法骨架不能被子类改变
  • 扩展性平衡:既要保证算法稳定,又要允许子类扩展
  • 方法粒度:如何合理划分抽象方法和具体方法
解决方案
// 良好的模板方法设计
public abstract class AbstractTemplate {
    // 模板方法使用final,防止子类重写
    public final void templateMethod() {
        // 1. 固定的前置处理
        beforeProcess();
      
        // 2. 核心业务逻辑,由子类实现
        doProcess();
      
        // 3. 固定的后置处理
        afterProcess();
      
        // 4. 可选的钩子方法
        if (needAdditionalProcess()) {
            additionalProcess();
        }
    }
  
    // 抽象方法:核心业务逻辑
    protected abstract void doProcess();
  
    // 具体方法:固定逻辑,子类不能改变
    private void beforeProcess() {
        System.out.println("固定前置处理");
    }
  
    private void afterProcess() {
        System.out.println("固定后置处理");
    }
  
    // 钩子方法:可选扩展点
    protected boolean needAdditionalProcess() {
        return false;
    }
  
    protected void additionalProcess() {
        // 默认空实现
    }
}

3.2 重难点二:钩子方法的设计和使用

难点分析
  • 钩子方法命名:如何命名钩子方法,使其意图清晰
  • 钩子方法粒度:钩子方法应该提供多大的扩展能力
  • 钩子方法顺序:多个钩子方法的执行顺序如何设计
解决方案
// 钩子方法设计示例
public abstract class AbstractProcessor {
    public final void process() {
        // 主流程
        initialize();
        validate();
        processData();
        save();
        cleanup();
      
        // 钩子方法:可选的扩展点
        if (needAudit()) {
            audit();
        }
      
        if (needNotification()) {
            notify();
        }
      
        if (needMetrics()) {
            recordMetrics();
        }
    }
  
    protected abstract void processData();
  
    // 钩子方法:审计
    protected boolean needAudit() {
        return false;
    }
  
    protected void audit() {
        System.out.println("执行审计");
    }
  
    // 钩子方法:通知
    protected boolean needNotification() {
        return true; // 默认需要通知
    }
  
    protected void notify() {
        System.out.println("发送通知");
    }
  
    // 钩子方法:指标记录
    protected boolean needMetrics() {
        return false;
    }
  
    protected void recordMetrics() {
        System.out.println("记录指标");
    }
}

3.3 重难点三:模板方法模式的扩展性设计

难点分析
  • 扩展点设计:如何设计合理的扩展点
  • 版本兼容性:如何保证模板方法的向后兼容
  • 性能考虑:钩子方法对性能的影响
解决方案
// 可扩展的模板方法设计
public abstract class AbstractProcessor {
    // 模板方法,支持版本控制
    public final void process() {
        process(ProcessVersion.V1);
    }
  
    // 支持版本控制的模板方法
    public final void process(ProcessVersion version) {
        beforeProcess(version);
      
        switch (version) {
            case V1:
                processV1();
                break;
            case V2:
                processV2();
                break;
            default:
                processV1();
        }
      
        afterProcess(version);
    }
  
    // 版本1的处理流程
    private void processV1() {
        doProcess();
        if (needAdditionalProcess()) {
            additionalProcess();
        }
    }
  
    // 版本2的处理流程
    private void processV2() {
        doProcess();
        if (needAdditionalProcess()) {
            additionalProcess();
        }
        if (needAdvancedProcess()) {
            advancedProcess();
        }
    }
  
    protected abstract void doProcess();
  
    // 钩子方法:版本控制
    protected void beforeProcess(ProcessVersion version) {
        // 默认实现
    }
  
    protected void afterProcess(ProcessVersion version) {
        // 默认实现
    }
  
    protected boolean needAdditionalProcess() {
        return false;
    }
  
    protected void additionalProcess() {
        // 默认实现
    }
  
    protected boolean needAdvancedProcess() {
        return false;
    }
  
    protected void advancedProcess() {
        // 默认实现
    }
}

// 版本枚举
public enum ProcessVersion {
    V1, V2
}

3.4 重难点四:模板方法模式的测试

难点分析
  • 抽象类测试:如何测试抽象类
  • 模板方法测试:如何测试模板方法的执行流程
  • 钩子方法测试:如何测试钩子方法的各种情况
解决方案
// 测试抽象类的模板方法
public class AbstractProcessorTest {
  
    @Test
    public void testTemplateMethod() {
        // 创建测试用的具体实现
        AbstractProcessor processor = new AbstractProcessor() {
            @Override
            protected void doProcess() {
                System.out.println("测试处理");
            }
          
            @Override
            protected boolean needAdditionalProcess() {
                return true;
            }
          
            @Override
            protected void additionalProcess() {
                System.out.println("测试额外处理");
            }
        };
      
        // 测试模板方法
        processor.process();
      
        // 验证执行结果
        // 可以使用Mock对象验证方法调用
    }
  
    @Test
    public void testHookMethods() {
        // 测试钩子方法的不同情况
        AbstractProcessor processor1 = new AbstractProcessor() {
            @Override
            protected void doProcess() {
                // 实现
            }
          
            @Override
            protected boolean needAdditionalProcess() {
                return false; // 不执行额外处理
            }
        };
      
        AbstractProcessor processor2 = new AbstractProcessor() {
            @Override
            protected void doProcess() {
                // 实现
            }
          
            @Override
            protected boolean needAdditionalProcess() {
                return true; // 执行额外处理
            }
        };
      
        // 分别测试两种情况
        processor1.process();
        processor2.process();
    }
}

4. Spring中的源码分析

4.1 Spring中的模板方法模式应用

4.1.1 JdbcTemplate中的模板方法
// JdbcTemplate的核心模板方法
public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
  
    // 查询模板方法
    public <T> T query(String sql, ResultSetExtractor<T> rse) throws DataAccessException {
        return query(sql, rse, (Object[]) null);
    }
  
    public <T> T query(String sql, ResultSetExtractor<T> rse, Object... args) throws DataAccessException {
        return query(sql, rse, newArgPreparedStatementSetter(args));
    }
  
    public <T> T query(String sql, ResultSetExtractor<T> rse, PreparedStatementSetter pss) throws DataAccessException {
        return query(new SimplePreparedStatementCreator(sql), pss, rse);
    }
  
    // 核心模板方法实现
    public <T> T query(PreparedStatementCreator psc, PreparedStatementSetter pss, ResultSetExtractor<T> rse) throws DataAccessException {
        return execute(psc, new PreparedStatementCallback<T>() {
            @Override
            public T doInPreparedStatement(PreparedStatement ps) throws SQLException {
                ResultSet rs = null;
                try {
                    if (pss != null) {
                        pss.setValues(ps);
                    }
                    rs = ps.executeQuery();
                    return rse.extractData(rs);
                } finally {
                    JdbcUtils.closeResultSet(rs);
                }
            }
        });
    }
  
    // 执行模板方法
    public <T> T execute(PreparedStatementCreator psc, PreparedStatementCallback<T> action) throws DataAccessException {
        return execute(psc, action, true);
    }
  
    public <T> T execute(PreparedStatementCreator psc, PreparedStatementCallback<T> action, boolean closeResources) throws DataAccessException {
        if (logger.isDebugEnabled()) {
            String sql = getSql(psc);
            logger.debug("Executing prepared SQL statement" + (sql != null ? " [" + sql + "]" : ""));
        }
      
        Connection con = null;
        PreparedStatement ps = null;
        try {
            // 获取连接
            con = getConnection();
            // 创建PreparedStatement
            ps = psc.createPreparedStatement(con);
            // 应用语句设置器
            applyStatementSettings(ps);
            // 执行回调
            T result = action.doInPreparedStatement(ps);
            // 处理警告
            handleWarnings(ps);
            return result;
        } catch (SQLException ex) {
            // 释放资源
            if (closeResources) {
                JdbcUtils.closeStatement(ps);
                ps = null;
            }
            // 转换异常
            throw translateException("PreparedStatementCallback", sql, ex);
        } finally {
            if (closeResources) {
                JdbcUtils.closeStatement(ps);
                JdbcUtils.closeConnection(con);
            }
        }
    }
}
4.1.2 AbstractApplicationContext中的模板方法
// AbstractApplicationContext的模板方法
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {
  
    // 刷新容器的模板方法
    @Override
    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // 准备刷新
            prepareRefresh();
          
            // 获取BeanFactory
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
          
            // 准备BeanFactory
            prepareBeanFactory(beanFactory);
          
            try {
                // 允许BeanFactory的后处理
                postProcessBeanFactory(beanFactory);
              
                // 调用BeanFactoryPostProcessors
                invokeBeanFactoryPostProcessors(beanFactory);
              
                // 注册BeanPostProcessors
                registerBeanPostProcessors(beanFactory);
              
                // 初始化MessageSource
                initMessageSource();
              
                // 初始化ApplicationEventMulticaster
                initApplicationEventMulticaster();
              
                // 刷新特定上下文子类
                onRefresh();
              
                // 检查监听器Bean并注册
                registerListeners();
              
                // 实例化所有非懒加载的单例Bean
                finishBeanFactoryInitialization(beanFactory);
              
                // 完成刷新
                finishRefresh();
            } catch (BeansException ex) {
                if (logger.isWarnEnabled()) {
                    logger.warn("Exception encountered during context initialization - " +
                        "cancelling refresh attempt: " + ex);
                }
                // 销毁已创建的Bean
                destroyBeans();
                // 重置'active'标志
                cancelRefresh(ex);
                throw ex;
            } finally {
                // 重置公共内省缓存
                resetCommonCaches();
            }
        }
    }
  
    // 钩子方法:刷新特定上下文子类
    protected void onRefresh() throws BeansException {
        // 默认空实现,子类可以重写
    }
  
    // 钩子方法:准备刷新
    protected void prepareRefresh() {
        this.startupDate = System.currentTimeMillis();
        this.closed.set(false);
        this.active.set(true);
      
        if (logger.isInfoEnabled()) {
            logger.info("Refreshing " + this);
        }
      
        // 初始化属性源
        initPropertySources();
      
        // 验证必需属性
        getEnvironment().validateRequiredProperties();
    }
}
4.1.3 AbstractBeanFactory中的模板方法
// AbstractBeanFactory的模板方法
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
  
    // 获取Bean的模板方法
    @Override
    public Object getBean(String name) throws BeansException {
        return doGetBean(name, null, null, false);
    }
  
    // 核心模板方法
    protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
            @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
      
        final String beanName = transformedBeanName(name);
        Object bean;
      
        // 尝试从缓存中获取单例Bean
        Object sharedInstance = getSingleton(beanName);
        if (sharedInstance != null && args == null) {
            bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
        } else {
            // 检查Bean定义是否存在
            if (isPrototypeCurrentlyInCreation(beanName)) {
                throw new BeanCurrentlyInCreationException(beanName);
            }
          
            // 检查父BeanFactory
            BeanFactory parentBeanFactory = getParentBeanFactory();
            if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
                String nameToLookup = originalBeanName(name);
                if (parentBeanFactory instanceof AbstractBeanFactory) {
                    return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
                        nameToLookup, requiredType, args, typeCheckOnly);
                } else if (args != null) {
                    return (T) parentBeanFactory.getBean(nameToLookup, args);
                } else {
                    return parentBeanFactory.getBean(nameToLookup, requiredType);
                }
            }
          
            if (!typeCheckOnly) {
                markBeanAsCreated(beanName);
            }
          
            try {
                final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
                checkMergedBeanDefinition(mbd, beanName, args);
              
                // 确保依赖的Bean被初始化
                String[] dependsOn = mbd.getDependsOn();
                if (dependsOn != null) {
                    for (String dep : dependsOn) {
                        if (isDependent(beanName, dep)) {
                            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
                        }
                        registerDependentBean(dep, beanName);
                        try {
                            getBean(dep);
                        } catch (NoSuchBeanDefinitionException ex) {
                            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
                        }
                    }
                }
              
                // 创建Bean实例
                if (mbd.isSingleton()) {
                    sharedInstance = getSingleton(beanName, () -> {
                        try {
                            return createBean(beanName, mbd, args);
                        } catch (BeansException ex) {
                            destroySingleton(beanName);
                            throw ex;
                        }
                    });
                    bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
                } else if (mbd.isPrototype()) {
                    Object prototypeInstance = null;
                    try {
                        beforePrototypeCreation(beanName);
                        prototypeInstance = createBean(beanName, mbd, args);
                    } finally {
                        afterPrototypeCreation(beanName);
                    }
                    bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
                } else {
                    String scopeName = mbd.getScope();
                    final Scope scope = this.scopes.get(scopeName);
                    if (scope == null) {
                        throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
                    }
                    try {
                        Object scopedInstance = scope.get(beanName, () -> {
                            beforePrototypeCreation(beanName);
                            try {
                                return createBean(beanName, mbd, args);
                            } finally {
                                afterPrototypeCreation(beanName);
                            }
                        });
                        bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
                    } catch (IllegalStateException ex) {
                        throw new BeanCreationException(beanName, "Scope '" + scopeName + "' is not active for the current thread; consider " +
                            "defining a scoped proxy for this bean if you intend to refer to it from a singleton", ex);
                    }
                }
            } catch (BeansException ex) {
                if (containsSingleton(beanName)) {
                    throw ex;
                }
                throw new BeanCreationException(
                    mbd.getResourceDescription(), beanName, "Invalid bean definition with name '" + beanName + "'", ex);
            }
        }
      
        return adaptBeanInstance(name, bean, requiredType);
    }
  
    // 抽象方法:创建Bean实例
    protected abstract Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
            throws BeanCreationException;
  
    // 钩子方法:原型Bean创建前
    protected void beforePrototypeCreation(String beanName) {
        // 默认空实现
    }
  
    // 钩子方法:原型Bean创建后
    protected void afterPrototypeCreation(String beanName) {
        // 默认空实现
    }
}

4.2 Spring模板方法模式的特点

4.2.1 模板方法设计特点
  1. 算法骨架固定:核心流程不允许子类改变
  2. 扩展点丰富:提供多个钩子方法供子类扩展
  3. 异常处理完善:统一的异常处理机制
  4. 资源管理规范:统一的资源获取和释放
4.2.2 钩子方法使用特点
// Spring中钩子方法的典型使用
public abstract class AbstractApplicationContext {
  
    // 钩子方法:刷新特定上下文子类
    protected void onRefresh() throws BeansException {
        // 默认空实现,子类可以重写
    }
  
    // 钩子方法:准备刷新
    protected void prepareRefresh() {
        // 默认实现,子类可以重写
    }
  
    // 钩子方法:完成刷新
    protected void finishRefresh() {
        // 默认实现,子类可以重写
    }
}

// 具体实现类
public class GenericApplicationContext extends AbstractApplicationContext {
  
    @Override
    protected void onRefresh() throws BeansException {
        // 特定上下文的刷新逻辑
        super.onRefresh();
    }
  
    @Override
    protected void prepareRefresh() {
        // 特定上下文的准备逻辑
        super.prepareRefresh();
    }
}

5. 面试高频点

5.1 基础概念类问题

Q1: 什么是模板方法模式?有什么特点?

答案要点:

  • 定义:定义算法骨架,将步骤延迟到子类实现
  • 特点:算法结构固定,步骤可定制,代码复用
  • 核心:模板方法 + 抽象方法 + 钩子方法
Q2: 模板方法模式与策略模式的区别?

答案要点:

  • 模板方法模式:算法结构固定,步骤可定制
  • 策略模式:算法完全可替换
  • 使用场景:模板方法用于算法结构相同,策略模式用于算法完全不同

5.2 设计原理类问题

Q3: 模板方法模式的核心组件有哪些?

答案要点:

1. AbstractClass(抽象类)
   - templateMethod():模板方法
   - primitiveOperation():抽象方法
   - concreteOperation():具体方法
   - hook():钩子方法

2. ConcreteClass(具体类)
   - 实现抽象方法
   - 可选重写钩子方法
Q4: 钩子方法的作用是什么?

答案要点:

  • 扩展点:提供可选的扩展能力
  • 控制流程:控制某些步骤是否执行
  • 定制行为:允许子类定制特定行为
  • 向后兼容:保证模板方法的向后兼容性

5.3 实现细节类问题

Q5: 如何设计一个好的模板方法?

答案要点:

// 设计原则
1. 模板方法使用final,防止子类重写
2. 抽象方法定义核心业务逻辑
3. 具体方法实现固定逻辑
4. 钩子方法提供扩展点
5. 合理的方法粒度划分
Q6: 模板方法模式如何保证算法稳定性?

答案要点:

  • final关键字:模板方法使用final防止重写
  • 访问控制:合理使用访问修饰符
  • 方法设计:将可变部分抽象为方法
  • 文档规范:明确说明哪些方法可以重写

5.4 Spring应用类问题

Q7: Spring中哪些地方使用了模板方法模式?

答案要点:

1. JdbcTemplate:数据库操作模板
2. AbstractApplicationContext:应用上下文刷新
3. AbstractBeanFactoryBean创建和管理
4. AbstractTransactionalDataSource:事务管理
5. AbstractControllerWeb控制器基类
Q8: Spring的JdbcTemplate是如何使用模板方法模式的?

答案要点:

// 核心流程
1. 获取数据库连接
2. 创建PreparedStatement
3. 设置参数
4. 执行SQL(抽象方法)
5. 处理结果集
6. 释放资源

5.5 实际应用类问题

Q9: 在项目中如何应用模板方法模式?

答案要点:

// 应用场景
1. 数据处理流程:数据验证、处理、保存
2. 文件处理流程:读取、解析、转换、输出
3. 业务流程:审批、执行、记录、通知
4. 框架设计:提供扩展点的框架
Q10: 模板方法模式的优缺点是什么?

答案要点:
优点:

  • 代码复用,避免重复代码
  • 算法结构稳定,易于维护
  • 扩展性好,支持子类扩展
  • 符合开闭原则

缺点:

  • 类数量增加,系统复杂度提高
  • 继承关系,子类与父类耦合
  • 模板方法修改影响所有子类
  • 调试困难,流程分散在多个类中

5.6 源码分析类问题

Q11: Spring的AbstractApplicationContext.refresh()方法是如何设计的?

答案要点:

// 设计特点
1. 使用synchronized保证线程安全
2. 定义完整的容器刷新流程
3. 提供多个钩子方法供子类扩展
4. 统一的异常处理和资源管理
5. 支持不同应用上下文的定制
Q12: 如何测试模板方法模式?

答案要点:

// 测试策略
1. 测试抽象类:创建测试用的具体实现
2. 测试模板方法:验证执行流程
3. 测试钩子方法:测试不同条件分支
4. 使用Mock对象:验证方法调用
5. 集成测试:测试完整流程

5.7 设计模式对比类问题

Q13: 模板方法模式与其他模式的区别?

答案要点:

模式关系区别
策略模式组合算法完全可替换 vs 算法结构固定
工厂方法继承创建对象 vs 定义算法
命令模式组合请求封装 vs 算法定义
责任链组合处理链 vs 算法步骤
Q14: 什么时候使用模板方法模式?

答案要点:

// 使用场景判断
if (多个类有相同算法结构) {
    if (算法结构稳定) {
        if (需要子类定制步骤) {
            使用模板方法模式;
        }
    }
}

// 具体场景
1. 框架设计:提供扩展点
2. 业务流程:标准化流程
3. 数据处理:统一处理流程
4. 算法实现:算法结构相同

总结

模板方法模式是Spring框架中广泛使用的设计模式,它通过定义算法骨架和提供扩展点,实现了代码复用和灵活扩展的平衡。

关键要点

  1. 理解原理:掌握模板方法模式的核心思想和设计原则
  2. 掌握实现:学会设计模板方法和钩子方法
  3. Spring应用:理解Spring中模板方法模式的应用
  4. 实际应用:能够在项目中合理使用模板方法模式
  5. 测试方法:掌握模板方法模式的测试策略

通过深入学习模板方法模式,可以更好地理解Spring框架的设计思想,提升代码的可维护性和扩展性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值