<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    當EffectiveJava遇見Guava - 靜態工廠方法代替構造器(規則1)


    Effective Java中指出,使用靜態工廠方法代替構造器有幾大優勢:

    第一大優勢 - 他們有名稱。

    多個構造器只能通過匹配參數類型的順序不同來區分使用哪一個,這樣常常會導致用戶調用錯誤構造器,而靜態工程方法則不同,可以通過方法名清晰的指明用意。

    //本例只用來說明第一大優勢,請不要糾結其它問題 
    public class Foo {
    Set<Bar> bars;
    List<Car> cars;
    //構造器1
    private Foo(Set<Bar> bars) {
    this.bars = bars;
    }
    //構造器2
    private Foo(List<Car> cars) {
    this.cars = cars;
    }
    //構造器3
    private Foo(Set<Bar> bars, List<Car> cars) {
    this.bars = bars;
    this.cars = cars;
    }
    //靜態工廠方法1
    public static Foo newInstanceByBar(){
    return new Foo(new HashSet<Bar>());
    }
    //靜態工廠方法2
    public static Foo newInstanceByCar(){
    return new Foo(new ArrayList<Car>());
    }
    //靜態工廠方法3
    public static Foo newInstanceByAll(){
    return new Foo(new HashSet<Bar>(),new ArrayList<Car>());
    }
    public static void main(String[] args) {
    // 通過構造器創建實例,不好區分容易使用錯誤
    Foo fbar = new Foo(new HashSet<Bar>());
    Foo fcar = new Foo(new ArrayList<Car>());
    Foo fall = new Foo(new HashSet<Bar>(),new ArrayList<Car>());
    // 通過靜態工廠方法可以清晰的用方法名識別
    Foo fbar_static = Foo.newInstanceByBar();
    Foo fcar_static = Foo.newInstanceByCar();
    Foo fall_static = Foo.newInstanceByAll();
    }
    }
    class Bar {}
    class Car {}

    對于Guava,并沒有提供創建靜態工廠方法的工具,但整個Guava API到處都是靜態方法的實現,我們以Guava Collections Framewrok舉例說明。

    Guava對于第一大優勢有很多實現:

    List<Type> exactly100 = Lists.newArrayListWithCapacity(100);
    List<Type> approx100 = Lists.newArrayListWithExpectedSize(100);
    Set<Type> approx100Set = Sets.newHashSetWithExpectedSize(100);

    第二大優勢 - 不必在每次調用他們的時候都創建一個新對象。

    方便對象重用,還可以確保不可變的不會存在兩個相等的實例,如果a==b那么a.equals.(b)才會返回true ,如果能保證這一點,就可以使用==操作符來比較對象,會有很大的性能提升。

    第三大優勢 - 他們可以返回原返回類型的任何子類型的對象。

    這是一個非常強大的特性, Effective Java中列舉了API、SPI、服務提供框架的關系來說明:

    API(Service Interface): 服務公共接口 SPI(Service Provider Interface): 服務提供商接口 SPF(Service Provider Framework): 服務提供框架

    看例子:

    // 服務提供框架示意模型 - 服務API 
    public interface ServiceAPI {
    // 這里是服務指定的方法
    }
    // 服務提供框架示意模型 - 服務SPI
    public interface ServiceSPI {
    ServiceAPI newService();
    }
    // 服務提供框架示意模型實現
    // 不可實例化的類,用來注冊創建和提供訪問
    public class ServiceFramework {
    private ServiceFramework() {
    }// 強制防止實例化(規則4)

    // 映射服務名到服務
    private static final ConcurrentMap<String, ServiceSPI> spis = new MapMaker().makeMap();//使用Guava創建
    public static final String DEFAULT_SPI_NAME = "<def>";

    // 默認SPI注冊API
    public static void registerDefaultSPI(ServiceSPI spi) {
    registerSPI(DEFAULT_SPI_NAME, spi);
    }

    // 指定SPI注冊API
    public static void registerSPI(String name, ServiceSPI spi) {
    spis.put(name, spi);
    }

    // 服務訪問API
    public static ServiceAPI newInstance() {
    return newInstance(DEFAULT_SPI_NAME);
    }
    public static ServiceAPI newInstance(String name) {
    ServiceSPI spi = spis.get(name);
    if(spi == null)
    throw new IllegalArgumentException(
    "No provider registered with name: " + name);
    return spi.newService();
    }
    }
    Note
    靜態工程方法返回的對象所屬的類,在編寫這個包含靜態工廠方法的類時可以不必存在。上面的例子在編寫ServiceFramework類時,ServiceAPI的實現類并不存在。這大大增加了框架的靈活性。

    現在編寫客戶端測試程序

    // 簡單的服務提供框架測試程序 
    public class Test {
    public static void main(String[] args) {
    // 服務提供商執行下面的注冊
    ServiceFramework.registerDefaultSPI(DEFAULT_PROVIDER);
    ServiceFramework.registerSPI("comp", COMP_PROVIDER);
    ServiceFramework.registerSPI("armed", ARMED_PROVIDER);
    // 客戶端執行下面的創建
    ServiceAPI s1 = ServiceFramework.newInstance();
    ServiceAPI s2 = ServiceFramework.newInstance("comp");
    ServiceAPI s3 = ServiceFramework.newInstance("armed");
    System.out.printf("%s, %s, %s%n", s1, s2, s3);
    }
    private static ServiceSPI DEFAULT_PROVIDER = new ServiceSPI() {
    public ServiceAPI newService() {
    return new ServiceAPI() {
    @Override
    public String toString() {
    return "默認服務";
    }
    };
    }
    };
    private static ServiceSPI COMP_PROVIDER = new ServiceSPI() {
    public ServiceAPI newService() {
    return new ServiceAPI() {
    @Override
    public String toString() {
    return "Complementary 服務";
    }
    };
    }
    };
    private static ServiceSPI ARMED_PROVIDER = new ServiceSPI() {
    public ServiceAPI newService() {
    return new ServiceAPI() {
    @Override
    public String toString() {
    return "Armed 服務";
    }
    };
    }
    };
    }

    //輸出如下 , Complementary , Armed

    第四大優勢 - 在創建參數化類型實例的時候,他們使代碼變得更加簡潔。

    在JDK7之前,我們創建一個Collections大致是這么做的:

    List<TypeThatsTooLongForItsOwnGood> list = new ArrayList<TypeThatsTooLongForItsOwnGood>();

    JDK7發布以后,我們可以簡化成這樣:

    List<TypeThatsTooLongForItsOwnGood> list = new ArrayList<>();

    但是Guava還是寧愿使用靜態工程方法,因為真的非常方便:

    Set<Type> copySet = Sets.newHashSet(elements); 
    List<String> theseElements = Lists.newArrayList("alpha", "beta", "gamma");

    靜態工程方法的缺點

    • 類如果不含公有的或者受保護的構造器,就不能被子類化,這也許會因禍得福,因為它鼓勵開發人員使用復合,而不是繼承。

    • 他們與其他的靜態方法實際上沒有任何區別 如果API文檔沒有明確的說明這是一個靜態工程方法,就會很難識別出來。遵循標準的命名規范習慣,可以彌補這一劣勢,下面列出一些慣用命名:

      • valueOf - 這樣的靜態工廠方法實際上是類型轉換

      • of - valueOf的簡潔方式

      • getInstance - 返回實例通過方法參數描述,對于單例,該方法沒有參數,并返回唯一的實例

      • newInstance - 與getInstance不同的是,它返回的實例與所有其它實例都是不同的

      • getType - 像getInstance一樣,但是在工廠方法處于不同的類中的時候使用。Type表示i返回對象類型

      • newType - 像newInstance一樣,但是在工廠方法處于不同的類中的時候使用。Type表示i返回對象類型

    2013-05-29

    posted on 2013-05-30 17:09 kuuyee 閱讀(3885) 評論(1)  編輯  收藏 所屬分類: JEE

    評論

    # re: 當EffectiveJava遇見Guava - 靜態工廠方法代替構造器(規則1) 2013-05-31 12:41 11

    發現了:

    The project was not built since its build path is incomplete.

    Cannot find the class file for com.aaap.workflow.engine.WorkFlowSupportSes. Fix the build path then try building this project

    The type com.aaap.workflow.services.ForwardNodesFacadeSes cannot be resolved. It is indirectly referenced from required .class

    意思是“工程需要用的包沒有引導入完全,沒有找到需要的類文件,請修改buildPath后重新編譯項目”

    和同事一比對,果然少引入了若干包,引入缺少的幾個包后,重新編譯,Problems視圖里提示的“”信息沒了。

    現在勾選了重新編譯,再修改,保存,編譯一閃而過~~ 正常啦!!
      回復  更多評論   

    導航

    <2013年5月>
    2829301234
    567891011
    12131415161718
    19202122232425
    2627282930311
    2345678

    統計

    隨筆分類(139)

    Linux內核

    搜索

    •  

    積分與排名

    • 積分 - 319450
    • 排名 - 177

    最新評論

    閱讀排行榜

    主站蜘蛛池模板: 免费夜色污私人影院在线观看| **一级毛片免费完整视| 国产精品免费_区二区三区观看 | 国产精品亚洲午夜一区二区三区| 18禁止看的免费污网站| 亚洲最新永久在线观看| 亚洲AV日韩综合一区尤物| 久久久高清免费视频| 亚洲中文字幕无码中文字| 歪歪漫画在线观看官网免费阅读| 国产精品亚洲一区二区麻豆| 性一交一乱一视频免费看| 日韩在线视精品在亚洲| 亚洲A∨精品一区二区三区| yellow视频免费看| 久久精品国产亚洲AV果冻传媒| 亚洲精品美女久久7777777| 日韩精品免费电影| 夜夜爽妓女8888视频免费观看| 亚洲无码视频在线| 久久99精品国产免费观看| 亚洲宅男天堂a在线| 国产人成免费视频| 免费国产污网站在线观看| 少妇中文字幕乱码亚洲影视| 免费一本色道久久一区| 日本一区二区在线免费观看| 亚洲AV无码第一区二区三区| 国产成人免费午夜在线观看| 精品久久久久久亚洲| 在线人成精品免费视频| 国产亚洲婷婷香蕉久久精品| 少妇人妻偷人精品免费视频| 色老板亚洲视频免在线观| 国产综合亚洲专区在线| 国产91免费视频| 偷自拍亚洲视频在线观看| 国产成人免费手机在线观看视频 | 国产成人免费ā片在线观看| 国产精品小视频免费无限app | 国产高清在线精品免费软件 |