ServiceLoader服務提供者模式,實現動態插件加載,類責任鏈模式

ServiceLoader服務提供者模式,實現動態插件加載,類責任鏈模式

ServiceLoader的功能比ClassLoader簡單,它可以幫我們獲取所有實現了某接口或基類的類。當然前提是ClassLoader已經加載過的類。舉個例子:
定義一個接口:

public interface IService {  
    public String sayHello();  

    public String getScheme();  
}

以及兩個實現類:

public class HDFSService implements IService {  

    @Override  
    public String sayHello() {  
        return "Hello HDFS!!";  
    }  

    @Override  
    public String getScheme() {  
        return "hdfs";  
    }  
}

public class LocalService implements IService {  

    @Override  
    public String sayHello() {  
        return "Hello Local!!";  
    }  

    @Override  
    public String getScheme() {  
        return "local";  
    }  

}

將 HDFSService 和 LocalService 打包成 jar,java包的 META-INFO/services 下以IService這個類的全名來新建立一個文件,文件中的內容爲兩個實現類的全名:

org.hadoop.java.HDFSService
org.hadoop.java.LocalService

我們通過一下方式來調用對應的實現類:

public class ServiceLoaderTest {  
    public static void main(String[] args) {  
        //need to define related class full name in /META-INF/services/....  
        ServiceLoader<IService> serviceLoader = ServiceLoader  
                .load(IService.class);  
        for (IService service : serviceLoader) {  
            System.out.println(service.getScheme()+"="+service.sayHello());  
        }  
    }  

}

插件模式

Netbean的插件就是使用ServiceLoader動態加載。先用類加載器將新的插件jar包加載到JVM,然後就可以使用ServiceLoader調用。

類責任鏈模式

有時候我們的程序需要根據匹配的條件,執行某段代碼,如:

if (optionA) {
    if (optionB) {
        doSomething1();
    } else {
        doSomething2();
    }
} else {
    doSomething3();
}

直接用if else條件判斷,比較複雜,不好維護。
類似上面的代碼,根據不同的輸入選項或命令行參數等調用不同的方法來完成某些操作,而不是單純的返回數據。因此,這些選項是爲了確定現在這個request是誰的職責,而這正是“責任鏈模式”要解決的問題!本節的標題爲“類責任鏈模式”,表示我的解決方案是類似“責任鏈模式”,並不嚴格和它保持一致,但核心思想是一致的:使多個對象都有機會處理請求。

因此,每個RequestHandler都需提供一個接口判斷自己能否處理當前請求;如果能處理,則Client調用另一個執行的接口:

public interface Handler {
    public boolean accept(Properties options);
    public void execute();
}

於是,上面的分支結構對應三個獨立的Handler類:

public class RequestHandler1 implements Handler {
    public boolean accept(Properties options) {
        return options.getProperty("A") != null
            && options.getProperty("B") != null;
    }

    public void execute() {
        doSomething1();
    }
}

public class RequestHandler2 implements Handler {
    public boolean accept(Properties options) {
        return options.getProperty("A") != null
            && options.getProperty("B") == null;
    }

    public void execute() {
        doSomething2();
    }
}

public class RequestHandler3 implements Handler {
    public boolean accept(Properties options) {
        return options.getProperty("A") == null;
    }

    public void execute() {
        doSomething3();
    }
}

接下來還需要一個額外的管理類負責這些類的實例化的請求的分發:

import java.util.ServiceLoader;
import java.util.Iterator;

public class Manager {
    private static Arraylist;
    static {
        list = new Array();

        ServiceLoaderloader = ServiceLoader.load(Handler.class);
        Iteratorit = loader.iterator();
        while (it.hasNext()) {
            list.add(it.next());
        }
    }

    public static void process(Properties options) {
        for (Handler handler : list) {
            if (handler.accept(options)) {
                handler.execute();
            }
        }
    }
}

上面代碼使用了服務加載功能自動實例化所有註冊過的Handler子類,如果你還不瞭解它的原理,可查看相應的API文檔。有了這些代碼,已經萬事具備!也許你已經發現,這樣的設計和JDBC的接口不謀而合:Manager對應java.sql.DriverManager、Handler對應java.sql.Driver、RequestHandler這些類則對應數據庫廠商自己實現的驅動程序。

基於這樣的框架,它的代碼總量也許比原來的要多,但你不再需要在一堆if else中仔細推敲代碼執行的前提條件,所有的前提條件都在accept函數裏;添加新的功能所要做的僅需實現一個新的類,無須修改現有代碼,符合開閉原則。

Reference

類責任鏈模式
轉一篇很不錯的介紹NetBeans的文章
http://blog.csdn.net/kokojhuang/article/details/8273303


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章