如何在Spring中使用責任鏈設計模式

如何在Spring中使用責任鏈設計模式

筆者文筆功力尚淺,若有不妥,請慷慨指出,一定感激涕零git

本片文章不是講Spring源碼中使用責任鏈的設計實例,而是會講在Spring中如何設計本身的責任鏈而且如何調用。github

責任鏈設計模式做爲咱們經常使用的設計模式之一,用途很是的廣,例如在一些流程化的執行中、或者是一些動態攔截中咱們均可以使用責任鏈設計模式進行設計需求,從而使咱們的項目不管是可用性仍是可擴展性都會很是的好。設計模式

你們對於責任鏈還有不瞭解的能夠看我以前的博文設計模式——責任鏈模式框架

如何定義鏈條

在Java開發中咱們若是想要本身定義一個鏈條,其實很是簡單,也就定義一個抽象類,而後定義幾個實現方法,而後設置其next屬性便可,可是在Spring中如何將框架與咱們的鏈條結合起來呢?其實這裏用到了三個註解@Component@Order@PostConstructide

  • @Component:將咱們的子類交給Spring管理
  • @Order:定義咱們鏈條的順序
  • @PostConstruct:程序啓動時將咱們鏈條組合起來

接下來咱們直接看代碼,首先來看抽象類,其實責任鏈的抽象類基本上都同樣的。ui

public abstract class PrintChainPattern {

    private PrintChainPattern next;

    public final void print() {
        String message = getMessage();

        log.info("{} : {}",message,message);
        if (getNext()!=null){
            getNext().print();
        }
    }
    public abstract String getMessage();
}

而後咱們看實現類,後面有四個實現類,依次返回是twothreefour@Order註解中數字依次遞增。這裏只演示第一個實現類的代碼。this

@Order(1)
@Component
public class OnePrintChainPattern extends PrintChainPattern{
    @Override
    public String getMessage() {
        return "one";
    }
}

接下來就到了如何利用Spring來組裝咱們的鏈條了設計

@Configuration
public class InitPrintChainPattern {

    @Autowired
    private List<PrintChainPattern> printChainPatterns;

    @PostConstruct
    private void initPrintChainPattern(){
        Collections.sort(printChainPatterns, AnnotationAwareOrderComparator.INSTANCE);

        int size = printChainPatterns.size();
        for (int i = 0; i < size; i++) {
            if (i == size-1){
                printChainPatterns.get(i).setNext(null);
            }else {
                printChainPatterns.get(i).setNext(printChainPatterns.get(i+1));
            }
        }
    }

    public void print(int index){
        printChainPatterns.get(index-1).print();
    }
}

這裏咱們能夠看到在@PostConstruct 方法中咱們作了兩件事code

  1. List<PrintChainPattern>中按照@Order註解的數字進行排序
  2. 依次設置每一個節點的next值

這樣咱們就已經將這個鏈條組合了起來。接下來咱們就能夠隨意的對這個鏈條進行操做,例如我下面的print()方法中,就是根據傳進來的值的不一樣會從不一樣的節點進行執行。對象

如何在抽象類中使用@Autowired

在上面咱們已經將咱們鏈條組合了起來,可是若是咱們的全部子類都公有一些類的話,那麼這個類就要放在抽象類中。那麼若是這個類咱們想要從Spring的容器中取得呢?

好比咱們有以下的類交給了Spring管理,咱們全部子類都要使用這個類。

@Bean
public User setUser(){
    return User.builder().name("張三").age(14).build();
}

只須要在抽象類中定義一次便可,只須要在set方法上加@Autowired註解就可以將Spring容器中的類給注入進來。

private User user;

@Autowired
public void setUser(User user){
    this.user = user;
}

而後在子類中直接調用getUser()方法就行

@Override
public String getMessage() {
    log.info("name:{},age:{}",getUser().getName(),getUser().getAge());
    return "one";
}

如何在枚舉類中使用@Autowired

爲何要在枚舉類中使用@Autowired,是由於我在作需求時將責任鏈設計模式和策略模式結合起來作了,關於策略模式不明白的話能夠看我以前的文章設計模式——策略模式。咱們可使用枚舉類使咱們的代碼更加清晰可見。

咱們定義一個簡單的枚舉策略模式的枚舉類。例如咱們在這裏面要使用Spring容器中得了類的話,咱們該如何寫呢?例如仍是User類。

public enum  HumanEnum {

    MAN("man"){
        @Override
        public void invoke() {
            log.info("i am man");
        }
    },
    WOMAN("woman"){
        @Override
        public void invoke() {
            log.info("i am woman");
        }
    };
    
    String value;

    HumanEnum(String value){
        this.value = value;
    }

    public abstract void invoke();
}

只須要在枚舉類中定義一個內部類,而後將注入進來的類賦值給枚舉類便可。

User user;

public void setUse(User user){
    this.user = user;
}

@Component
public static class HumanEnumInjector{

    @Autowired
    private  User user;

    @PostConstruct
    public void setValue(){
        for (HumanEnum humanEnum : EnumSet.allOf(HumanEnum.class)){
            humanEnum.setUse(user);
        }
    }
}

本文代碼地址

總結

面向對象的三大特性:封裝、繼承、多態

  1. 大部分的設計模式都是圍繞着面向對象的三大特性進行演化的
  2. @Autowired也能夠定義在方法上,以前只是習慣將其定義在字段上
  3. 注重基礎,複雜的設計確定也是經過一個一個簡單的設計將其拼合的
相關文章
相關標籤/搜索