<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 閱讀(3882) 評論(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內核

    搜索

    •  

    積分與排名

    • 積分 - 319320
    • 排名 - 177

    最新評論

    閱讀排行榜

    主站蜘蛛池模板: 国产免费黄色无码视频| 五月婷婷亚洲综合| 久久青青草原国产精品免费| 亚洲国产无线乱码在线观看| 中文字幕亚洲色图| 亚洲宅男天堂在线观看无病毒| 精品无码国产污污污免费| 国产大片91精品免费观看不卡| 大地资源网高清在线观看免费| 黄网站在线播放视频免费观看 | 免费看无码特级毛片| 免费精品久久久久久中文字幕| 亚洲最大天堂无码精品区| 亚洲午夜精品在线| 亚洲综合激情另类小说区| 亚洲av无码专区在线播放| 亚洲免费视频一区二区三区| 国产伦精品一区二区三区免费下载| 国语成本人片免费av无码| 999国内精品永久免费观看| 日韩人妻一区二区三区免费| 国产自国产自愉自愉免费24区| caoporm碰最新免费公开视频| 日韩在线观看免费| 免费一级毛suv好看的国产网站 | 日韩免费电影在线观看| 久久不见久久见免费影院| 免费成人福利视频| 中文字幕无码播放免费| 成人免费在线看片| 无码日韩人妻av一区免费| 一二三四视频在线观看中文版免费| 无码国产精品一区二区免费式影视 | 日韩精品极品视频在线观看免费| 国色精品va在线观看免费视频 | 亚洲一区二区三区香蕉| 亚洲男同帅GAY片在线观看| 亚洲永久精品ww47| 亚洲AV无码久久精品成人| 亚洲成在人天堂在线| 亚洲狠狠ady亚洲精品大秀|