什么是模板方法設計模式?
模板方法設計模式是一種行為型設計模式,它定義了一個算法的骨架,并將一些步驟的具體實現延遲到子類中。模板方法模式可以幫助確保在算法的不同部分中保持一致性,同時也允許子類根據需要進行具體實現。
模板方法模式的關鍵特點包括:
- 抽象類: 定義一個抽象類,其中包含一個模板方法,該方法定義了算法的骨架。這個抽象類可以包含一些通用的實現或共享的代碼。
- 具體步驟: 在抽象類中,將算法的不同步驟定義為抽象方法。這些步驟需要由具體的子類來實現。
- 模板方法: 這是算法的核心方法,它包含了算法的基本步驟,可能包括調用不同的具體步驟方法。這個方法通常是 final,以防止子類修改整體算法結構。
- 鉤子方法:鉤子方法是一種在抽象類中定義的方法,子類可以選擇是否覆蓋它。這些方法通常是空方法,可以在模板方法的執行過程中被調用,以便影響算法的某些特定步驟。
模板方法設計模式的優點包括:
- 提供了一種統一的算法結構,使得算法在不同的子類中保持一致。
- 提供了代碼復用和共享的機制,避免了重復的代碼。
- 允許子類根據需要覆蓋特定步驟的實現,實現了開閉原則。
一個典型的模板方法設計模式的例子是 Java 中的 AbstractList 類,它定義了訪問和修改列表的算法框架,然后由具體的子類(如 ArrayList、LinkedList 等)實現不同的細節。
總之,模板方法設計模式允許您定義一個算法的骨架,然后將一些具體的步驟延遲到子類中實現。這種方式提高了代碼的復用性和可維護性,同時也確保了算法的一致性。
模板抽象類
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();@Overridepublic void afterPropertiesSet(){SynFileFactory.registerHandler(getFileName(), this);}}
在這個代碼片段中,AbstractSynFileHandler 是一個抽象類,定義了一個模板方法模式的結構。模板方法模式的關鍵是抽象類中的模板方法,該方法定義了一個算法的基本步驟,但是某些步驟的具體實現留給了子類來完成。
在這個代碼中,parseFile 和 getFileName方法是需要子類實現的具體步驟。這些步驟的具體實現因應用而異,所以它們被定義為抽象方法。然后,在 afterPropertiesSet方法中,SynFileFactory.registerHandler 方法被調用,該方法將當前實例注冊到 SynFileFactory中,實現了模板方法模式中的模板方法調用和延遲到子類的具體實現。
子類實現
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> {@Overridepublic 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]);}}@Overridepublic String getFileName() {return SiebelCons.ACCOUNT;}
}