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

什么是模板方法设计模式?
模板方法设计模式是一种行为型设计模式,它定义了一个算法的骨架,并将一些步骤的具体实现延迟到子类中。模板方法模式可以帮助确保在算法的不同部分中保持一致性,同时也允许子类根据需要进行具体实现。
模板方法模式的关键特点包括:

  • 抽象类: 定义一个抽象类,其中包含一个模板方法,该方法定义了算法的骨架。这个抽象类可以包含一些通用的实现或共享的代码。
  • 具体步骤: 在抽象类中,将算法的不同步骤定义为抽象方法。这些步骤需要由具体的子类来实现。
  • 模板方法: 这是算法的核心方法,它包含了算法的基本步骤,可能包括调用不同的具体步骤方法。这个方法通常是 final,以防止子类修改整体算法结构。
  • 钩子方法:钩子方法是一种在抽象类中定义的方法,子类可以选择是否覆盖它。这些方法通常是空方法,可以在模板方法的执行过程中被调用,以便影响算法的某些特定步骤。

模板方法设计模式的优点包括:

  • 提供了一种统一的算法结构,使得算法在不同的子类中保持一致。
  • 提供了代码复用和共享的机制,避免了重复的代码。
  • 允许子类根据需要覆盖特定步骤的实现,实现了开闭原则。

一个典型的模板方法设计模式的例子是 Java 中的 AbstractList 类,它定义了访问和修改列表的算法框架,然后由具体的子类(如 ArrayList、LinkedList 等)实现不同的细节。
总之,模板方法设计模式允许您定义一个算法的骨架,然后将一些具体的步骤延迟到子类中实现。这种方式提高了代码的复用性和可维护性,同时也确保了算法的一致性。

模板抽象类

bash 复制代码
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

/**
 * @author Wang
 */
@Slf4j
public abstract class AbstractSynFileHandler<T> implements InitializingBean {

    /**
     * parseFile
     * @param inputStream   inputStream
     * @return  <T> List<T>
     * @throws IOException  IOException
     */
    public abstract List<T> parseFile(InputStream inputStream) throws IOException;

    /**
     * getHandlerName
     * @return  String
     */
    public abstract String getFileName();


    @Override
    public void afterPropertiesSet(){
        SynFileFactory.registerHandler(getFileName(), this);
    }

}

在这个代码片段中,AbstractSynFileHandler 是一个抽象类,定义了一个模板方法模式的结构。模板方法模式的关键是抽象类中的模板方法,该方法定义了一个算法的基本步骤,但是某些步骤的具体实现留给了子类来完成。
在这个代码中,parseFilegetFileName 方法是需要子类实现的具体步骤。这些步骤的具体实现因应用而异,所以它们被定义为抽象方法。然后,在 afterPropertiesSet 方法中,SynFileFactory.registerHandler 方法被调用,该方法将当前实例注册到 SynFileFactory中,实现了模板方法模式中的模板方法调用和延迟到子类的具体实现。

子类实现

bash 复制代码
import cn.hutool.core.text.CharSequenceUtil;
import com.woodare.cdw.core.Cons;
import com.woodare.cdw.core.SiebelCons;
import com.woodare.cdw.jpa.entity.AccountEntity;
import com.woodare.cdw.siebel.AbstractSynFileHandler;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

/**
 * @author Wang
 */
@RequiredArgsConstructor
@Slf4j
@Component
public class AccountHandler extends AbstractSynFileHandler<AccountEntity> {


    @Override
    public List<AccountEntity> parseFile(InputStream inputStream) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
        List<AccountEntity> list = new ArrayList<>();
        String line;
        int lineNum = 0;
        while ((line = reader.readLine()) != null) {
            if (lineNum == 0) {
                lineNum++;
                continue;
            }
            String[] values = line.split(Cons.Delimiter.WAVY);
            AccountEntity accountEntity = new AccountEntity();
            this.buildEntity(values, accountEntity);
            list.add(accountEntity);
            lineNum++;
        }
        return list;
    }

    private void buildEntity(String[] values, AccountEntity accountEntity) {
        if(CharSequenceUtil.isNotBlank(values[0])){
            accountEntity.setSiebelId(values[0]);
        }
        if(CharSequenceUtil.isNotBlank(values[1])){
            accountEntity.setFirstName(values[1]);
        }
        if(CharSequenceUtil.isNotBlank(values[2])){
            accountEntity.setLastName(values[2]);
        }
        if(CharSequenceUtil.isNotBlank(values[3])){
            accountEntity.setMiddleInitial(values[3]);
        }
        if(CharSequenceUtil.isNotBlank(values[4])){
            accountEntity.setEmail(values[4]);
        }
        if(CharSequenceUtil.isNotBlank(values[5])){
            accountEntity.setCellPhone(values[5]);
        }
        if(CharSequenceUtil.isNotBlank(values[6])){
            accountEntity.setAddress1(values[6]);
        }
        if(CharSequenceUtil.isNotBlank(values[7])){
            accountEntity.setAddress2(values[7]);
        }
        if(CharSequenceUtil.isNotBlank(values[8])){
            accountEntity.setCity(values[8]);
        }
        if(CharSequenceUtil.isNotBlank(values[9])){
            accountEntity.setState(values[9]);
        }
        if(CharSequenceUtil.isNotBlank(values[10])){
            accountEntity.setZip(values[10]);
        }
    }

    @Override
    public String getFileName() {
        return SiebelCons.ACCOUNT;
    }
}
相关推荐
不许哈哈哈3 分钟前
基于百度云ORC与阿里大语言模型的自动评分系统
python·语言模型·百度云
Unity官方开发者社区17 分钟前
《Cryptical Path》开发诀窍:像玩游戏一样开发一款类Rogue游戏
java·游戏·玩游戏
敲代码的 蜡笔小新19 分钟前
【行为型之迭代器模式】游戏开发实战——Unity高效集合遍历与场景管理的架构精髓
unity·设计模式·c#·迭代器模式
_星辰大海乀20 分钟前
表的设计、聚合函数
java·数据结构·数据库·sql·mysql·数据库开发
dhxhsgrx27 分钟前
PYTHON训练营DAY27
开发语言·python
IT成长史29 分钟前
deepseek梳理java高级开发工程师微服务面试题-进阶版
java·spring cloud·微服务
zkmall39 分钟前
Java + 鸿蒙双引擎:ZKmall开源商城如何定义下一代B2C商城技术标准?
java·开源·harmonyos
陌路物是人非40 分钟前
uniapp取消浏览自动填充
java·服务器·uni-app
獨枭41 分钟前
使用 163 邮箱实现 Spring Boot 邮箱验证码登录
java·spring boot·后端
伍六星42 分钟前
maven和npm区别是什么
java·npm·maven