當(dāng)EffectiveJava遇見Guava - 靜態(tài)工廠方法代替構(gòu)造器(規(guī)則1)


          Effective Java中指出,使用靜態(tài)工廠方法代替構(gòu)造器有幾大優(yōu)勢(shì):

          第一大優(yōu)勢(shì) - 他們有名稱。

          多個(gè)構(gòu)造器只能通過匹配參數(shù)類型的順序不同來區(qū)分使用哪一個(gè),這樣常常會(huì)導(dǎo)致用戶調(diào)用錯(cuò)誤構(gòu)造器,而靜態(tài)工程方法則不同,可以通過方法名清晰的指明用意。

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

          對(duì)于Guava,并沒有提供創(chuàng)建靜態(tài)工廠方法的工具,但整個(gè)Guava API到處都是靜態(tài)方法的實(shí)現(xiàn),我們以Guava Collections Framewrok舉例說明。

          Guava對(duì)于第一大優(yōu)勢(shì)有很多實(shí)現(xiàn):

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

          第二大優(yōu)勢(shì) - 不必在每次調(diào)用他們的時(shí)候都創(chuàng)建一個(gè)新對(duì)象。

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

          第三大優(yōu)勢(shì) - 他們可以返回原返回類型的任何子類型的對(duì)象。

          這是一個(gè)非常強(qiáng)大的特性, Effective Java中列舉了API、SPI、服務(wù)提供框架的關(guān)系來說明:

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

          看例子:

          // 服務(wù)提供框架示意模型 - 服務(wù)API 
          public interface ServiceAPI {
          // 這里是服務(wù)指定的方法
          }
          // 服務(wù)提供框架示意模型 - 服務(wù)SPI
          public interface ServiceSPI {
          ServiceAPI newService();
          }
          // 服務(wù)提供框架示意模型實(shí)現(xiàn)
          // 不可實(shí)例化的類,用來注冊(cè)創(chuàng)建和提供訪問
          public class ServiceFramework {
          private ServiceFramework() {
          }// 強(qiáng)制防止實(shí)例化(規(guī)則4)

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

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

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

          // 服務(wù)訪問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
          靜態(tài)工程方法返回的對(duì)象所屬的類,在編寫這個(gè)包含靜態(tài)工廠方法的類時(shí)可以不必存在。上面的例子在編寫ServiceFramework類時(shí),ServiceAPI的實(shí)現(xiàn)類并不存在。這大大增加了框架的靈活性。

          現(xiàn)在編寫客戶端測(cè)試程序

          // 簡(jiǎn)單的服務(wù)提供框架測(cè)試程序 
          public class Test {
          public static void main(String[] args) {
          // 服務(wù)提供商執(zhí)行下面的注冊(cè)
          ServiceFramework.registerDefaultSPI(DEFAULT_PROVIDER);
          ServiceFramework.registerSPI("comp", COMP_PROVIDER);
          ServiceFramework.registerSPI("armed", ARMED_PROVIDER);
          // 客戶端執(zhí)行下面的創(chuàng)建
          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 "默認(rèn)服務(wù)";
          }
          };
          }
          };
          private static ServiceSPI COMP_PROVIDER = new ServiceSPI() {
          public ServiceAPI newService() {
          return new ServiceAPI() {
          @Override
          public String toString() {
          return "Complementary 服務(wù)";
          }
          };
          }
          };
          private static ServiceSPI ARMED_PROVIDER = new ServiceSPI() {
          public ServiceAPI newService() {
          return new ServiceAPI() {
          @Override
          public String toString() {
          return "Armed 服務(wù)";
          }
          };
          }
          };
          }

          //輸出如下 認(rèn)務(wù), Complementary 務(wù), Armed 務(wù)

          第四大優(yōu)勢(shì) - 在創(chuàng)建參數(shù)化類型實(shí)例的時(shí)候,他們使代碼變得更加簡(jiǎn)潔。

          在JDK7之前,我們創(chuàng)建一個(gè)Collections大致是這么做的:

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

          JDK7發(fā)布以后,我們可以簡(jiǎn)化成這樣:

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

          但是Guava還是寧愿使用靜態(tài)工程方法,因?yàn)檎娴姆浅7奖悖?/p>

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

          靜態(tài)工程方法的缺點(diǎn)

          • 類如果不含公有的或者受保護(hù)的構(gòu)造器,就不能被子類化,這也許會(huì)因禍得福,因?yàn)樗膭?lì)開發(fā)人員使用復(fù)合,而不是繼承。

          • 他們與其他的靜態(tài)方法實(shí)際上沒有任何區(qū)別 如果API文檔沒有明確的說明這是一個(gè)靜態(tài)工程方法,就會(huì)很難識(shí)別出來。遵循標(biāo)準(zhǔn)的命名規(guī)范習(xí)慣,可以彌補(bǔ)這一劣勢(shì),下面列出一些慣用命名:

            • valueOf - 這樣的靜態(tài)工廠方法實(shí)際上是類型轉(zhuǎn)換

            • of - valueOf的簡(jiǎn)潔方式

            • getInstance - 返回實(shí)例通過方法參數(shù)描述,對(duì)于單例,該方法沒有參數(shù),并返回唯一的實(shí)例

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

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

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

          2013-05-29

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

          評(píng)論

          # re: 當(dāng)EffectiveJava遇見Guava - 靜態(tài)工廠方法代替構(gòu)造器(規(guī)則1) 2013-05-31 12:41 11

          發(fā)現(xiàn)了:

          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

          意思是“工程需要用的包沒有引導(dǎo)入完全,沒有找到需要的類文件,請(qǐng)修改buildPath后重新編譯項(xiàng)目”

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

          現(xiàn)在勾選了重新編譯,再修改,保存,編譯一閃而過~~ 正常啦!!
            回復(fù)  更多評(píng)論   

          導(dǎo)航

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

          統(tǒng)計(jì)

          隨筆分類(139)

          Linux內(nèi)核

          搜索

          •  

          積分與排名

          • 積分 - 320259
          • 排名 - 178

          最新評(píng)論

          閱讀排行榜

          主站蜘蛛池模板: 洛扎县| 五大连池市| 内黄县| 密云县| 西城区| 延边| 绥江县| 准格尔旗| 永寿县| 怀来县| 绩溪县| 加查县| 陵川县| 雷波县| 师宗县| 桃园县| 扎兰屯市| 兰考县| 葫芦岛市| 穆棱市| 乐陵市| 松溪县| 安徽省| 和顺县| 泽库县| 从江县| 洪泽县| 绿春县| 上林县| 建湖县| 武鸣县| 文水县| 郧西县| 斗六市| 建昌县| 龙口市| 祁阳县| 深圳市| 石屏县| 商洛市| 榆中县|