考慮用靜態(tài)工廠方法代替構(gòu)造器

靜態(tài)工廠方法與構(gòu)造器相比具有幾大優(yōu)勢:

1. 有名稱。比較清晰,且代碼更易閱讀。
例如:BigInteger.probablePrime(int, Random).

2. 不必在每次調(diào)用它們的時(shí)候都創(chuàng)建一個(gè)新對象。如果程序經(jīng)常請求創(chuàng)建相同的對象,并且創(chuàng)建對象的代價(jià)很高,則可以極大地提升性能。可以為重復(fù)的調(diào)用返回相同的對象。這種類被稱為實(shí)例受控的類,確保類為Singleton或者是不可實(shí)例化的,保證了不會(huì)存在兩個(gè)相等的實(shí)例,可以用==操作符來代替equals(Object)方法,提升性能。(枚舉類型保證了這一點(diǎn))
例一:

public static Boolean valueOf(boolean b) {
    return b ? Boolean.TRUE : Boolean.FALSE;
}

例二:

public class Singleton {

    private static volatile Singleton singleton;

    private Singleton () { }

    public static Singleton getInstance() {
        if(singleton == null) {
            synchronized(Singleton.class) {
                if(singleton == null) {
                    singleton = new Singleton();
                } 
            }
        }
        return singleton;
    }

}

3. 可以返回原返回類型的任何子類型的對象。
例一:java.util.Collections提供了不可修改集合,同步集合等等便利實(shí)現(xiàn)。
例二:java.util.EnumSet沒有公有的構(gòu)造器,只有靜態(tài)工廠方法。如果元素有64個(gè)或者更少,方法會(huì)返回一個(gè)RegalarEnumSet實(shí)例;如果元素有65個(gè)或者更多,方法就返回JumboEnumSet實(shí)例。
例三:服務(wù)提供者框架(Service Provider Framework),它有三個(gè)重要的組件:Service Interface 服務(wù)接口,Provider Registration API 提供者注冊API,Service Access API 服務(wù)訪問API。還有一個(gè)可選組件:Service Provider Interface 服務(wù)提供者接口,如果沒有這個(gè)組件,實(shí)現(xiàn)就按類名稱注冊,并通過反射方式進(jìn)行實(shí)例化。例如JDBC API,Connection就是服務(wù)接口,DriverManager.registerDriver是提供者注冊API,DriverManager.getConnection是服務(wù)訪問API,Driver就是服務(wù)提供者接口。

/**
 * Service Interface 服務(wù)接口:由提供者來實(shí)現(xiàn)
 * 音樂相關(guān)的基礎(chǔ)服務(wù)
 */
public interface BaseMusicService {
    
    /**
     * 播放音樂服務(wù)
     */
    void playMusic();
    
    // TODO 更多其他服務(wù)...

}
/**
 * Service Provider Interface 服務(wù)提供者接口:由提供者負(fù)責(zé)創(chuàng)建其服務(wù)實(shí)現(xiàn)的實(shí)例
 * 基礎(chǔ)音樂提供商
 */
public interface BaseMusicProvider {
    
    /**
     * 創(chuàng)建其服務(wù)實(shí)現(xiàn)的實(shí)例
     * @return
     */
    BaseMusicService newService();

}
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 應(yīng)用市場
 * 可進(jìn)行提供者的注冊
 * 可獲取服務(wù)的實(shí)例
 */
public class AppStore {
    
    // 該類不可實(shí)例化
    private AppStore() { }
    
    // 已注冊的服務(wù)提供商
    private static final Map<String, BaseMusicProvider> providers = 
            new ConcurrentHashMap<String, BaseMusicProvider>();
    
    // 默認(rèn)服務(wù)提供商的名稱
    public static final String DEFAULT_PROVIDER_NAME = "Default";
    
    // Provider Registration API 提供者注冊API:用來實(shí)現(xiàn)注冊提供者
    public static void registerDefaultProvider(BaseMusicProvider p) {
        registerProvider(DEFAULT_PROVIDER_NAME, p);
    }
    
    public static void registerProvider(String name, BaseMusicProvider p) {
        providers.put(name, p);
    }
    
    // Service Access API 服務(wù)訪問API:客戶端用來獲取服務(wù)實(shí)例的
    public static BaseMusicService newInstance() {
        return newInstance(DEFAULT_PROVIDER_NAME);
    }
    
    public static BaseMusicService newInstance(String name) {
        BaseMusicProvider p = providers.get(name);
        if(p == null){
            throw new IllegalArgumentException(
                    "No provider registered with name: " + name);
        }
        return p.newService();
    }

}
public class Test {

    public static void main(String[] args) {
        
        // 應(yīng)用市場注冊服務(wù)提供者
        AppStore.registerDefaultProvider(DEFAULT_PROVIDER);
        AppStore.registerProvider("QQ", QQ_PROVIDER);
        AppStore.registerProvider("NetEase", NETEASE_PROVIDER);
        
        // 用戶獲得不同的提供者提供的服務(wù)實(shí)例
        BaseMusicService s1 = AppStore.newInstance();
        BaseMusicService s2 = AppStore.newInstance("QQ");
        BaseMusicService s3 = AppStore.newInstance("NetEase");
        
        // 享受服務(wù),播放音樂
        s1.playMusic();
        s2.playMusic();
        s3.playMusic();
        
    }
    
    private static BaseMusicProvider DEFAULT_PROVIDER = new BaseMusicProvider() {

        @Override
        public BaseMusicService newService() {
            return DEFAULT_PROVIDER_SERVICE;
        }
        
    };
    
    private static BaseMusicService DEFAULT_PROVIDER_SERVICE = new BaseMusicService() {

        @Override
        public void playMusic() {
            System.out.println("默認(rèn)提供者開始播放音樂服務(wù)...");
        }
        
    };
    
    private static BaseMusicProvider QQ_PROVIDER = new BaseMusicProvider() {

        @Override
        public BaseMusicService newService() {
            return QQ_PROVIDER_SERVICE;
        }
        
    };
    
    private static BaseMusicService QQ_PROVIDER_SERVICE = new BaseMusicService() {

        @Override
        public void playMusic() {
            System.out.println("QQ音樂提供者開始播放音樂服務(wù)...");
        }
        
    };
    
    private static BaseMusicProvider NETEASE_PROVIDER = new BaseMusicProvider() {

        @Override
        public BaseMusicService newService() {
            return NETEASE_PROVIDER_SERVICE;
        }
        
    };
    
    private static BaseMusicService NETEASE_PROVIDER_SERVICE = new BaseMusicService() {

        @Override
        public void playMusic() {
            System.out.println("網(wǎng)易云音樂提供者開始播放音樂服務(wù)...");
        }
        
    };

}
----------------------------------------------------  
輸出:
默認(rèn)提供者開始播放音樂服務(wù)...
QQ音樂提供者開始播放音樂服務(wù)...
網(wǎng)易云音樂提供者開始播放音樂服務(wù)...

4. 創(chuàng)建參數(shù)化類型實(shí)例的時(shí)候,可以使代碼變得更簡潔。
例如:類型推導(dǎo)

Map<String, List<String>> m = new HashMap<String, List<String>>();

使用了靜態(tài)工廠方法,可以用下面代替上面的繁瑣的聲明。

public static <K, V> HashMap<K, V> newInstance() {
    return new HashMap<K, V>();
}

Map<String, List<String>> m = HashMap.newInstance();

靜態(tài)工廠方法的主要缺點(diǎn)在于:

1. 類如果不含公有的或受保護(hù)的構(gòu)造器,就不能被子類化。類A extends 類B時(shí),類B必須要有可用非私有的構(gòu)造器。

2. 與其他靜態(tài)方法實(shí)際上無區(qū)別。所以有以下慣用名稱:

  • valueOf——類型轉(zhuǎn)換。
  • of——valueOf更簡潔的替代。
  • getInstance——通過方法的參數(shù)返回實(shí)例。
  • newInstance——同上,并能確保返回的每個(gè)實(shí)例都與其他實(shí)例不同。
  • getType——類似getInstance,在工廠方法中處于不同的類使用。
  • newType——類似newInstance,在工廠方法中處于不同的類使用。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容