1. 程式人生 > >Effective Java 讀書筆記

Effective Java 讀書筆記

第二章  建立與銷燬物件

1、考慮用靜態工廠方法代替構造器

優點:

    1、有名稱

    2、不必在每次呼叫他們的時候都建立一個新的物件

    3、他們可以返回原返回型別的任何子型別物件

    4、使程式碼更簡潔

缺點:

    1、類如果不含公有的或者受保護的構造器,就不能被子類化

    2、與其他的靜態方法實際上沒有任何區別,不能一眼就看出來

        可以用一些慣用的名稱:

        valueOf

        Of

        getInstance

        newInstance

        getType

        NewType

關於第三條優點,這種靈活的靜態工廠方法可以構成 服務者提供框架(Service Provider Framework)

/**
 * 服務提供者框架
 * 多個服務提供者實現一個服務,系統為服務提供者的客戶端提供多個實現,並把他們從多個實現中解耦出來
 */
public class Services {

    private Services(){

    }

    private static final String DEFAULT_PROVIDER = "DEFAULT_PROVIDER";
    private static final ConcurrentHashMap<String,Provider> providers = new ConcurrentHashMap();

    /**
     * 註冊提供者
     * @param name
     * @param provider
     */
    public static void registProvider(String name,Provider provider){
        providers.put(name,provider);
    }

    /**
     * 註冊預設提供者
     * @param provider
     */
    public static void registDefaultProvider(Provider provider){
        providers.put(DEFAULT_PROVIDER,provider);
    }

    /**
     * 提供預設服務
     * @return
     */
    public static Service newInstance(){
        return newInstance(DEFAULT_PROVIDER);
    }

    /**
     * 根據相應條件提供特定服務
     * @param name
     * @return
     */
    public static Service newInstance(String name){
        Provider provider = providers.get(name);
        if(provider == null)
            throw new IllegalArgumentException("服務不存在");
        return provider.newService();
    }

    /**
     * 服務提供者介面
     */
    interface Provider{
        /**
         * 例項化一個服務
         * @return
         */
        Service newService();

        /**
         * 註冊提供者
         */
        void registProvider();
    }

    /**
     * 服務介面
     */
    interface Service{

        default  void say(){
            System.out.println("i am default");
        }

    }

}
/**
 * 服務A
 */
public class ServiceA implements Services.Service{

    public void say(){
        System.out.println("i am A");
    }

    /**
     *  服務提供者,負責註冊服務,構建服務類
     */
    static class ProviderA implements Services.Provider{

        public final static String NAME = "A";

        @Override
        public Services.Service newService() {
            return new ServiceA();
        }

        @Override
        public void registProvider() {
            Services.registProvider(NAME,this);
        }


    }

}




/**
 * 服務B
 */
public class ServiceB implements Services.Service{

    public void say(){
        System.out.println("i am B");
    }

    /**
     * 服務提供者,負責構建服務 向Services類註冊服務
     */
    static class ProviderB implements Services.Provider{

        public final static String NAME = "B";

        @Override
        public Services.Service newService() {
            return new ServiceB();
        }

        @Override
        public void registProvider() {
            Services.registProvider(NAME,this);
        }


    }

}

一個測試例子

public class Client {

    public static void main(String[] args){
        Services.Provider providerA = new ServiceA.ProviderA();
        Services.Provider providerB = new ServiceB.ProviderB();
        providerA.registProvider();
        providerB.registProvider();

        Services.Service service = Services.newInstance("B");
        service.say();
    }

}

最終列印

i am B

2、遇到多個構造器引數時要考慮用構建器

重疊構造器模式可行,但是當有許多引數的時候,客戶端程式碼會很難編寫,過多的構造器也不利於閱讀

使用構建器,優點

1、客戶端程式碼更加清晰,利於閱讀

2、可以在set方法或者build中對傳入引數進行驗證,及時丟擲異常

一個簡單的例子

/**
 * 不可變類,構造器私有
 */
public class Service {

    private final String name;

    private  final int age;

    private  final int height;

    private final int weight;

    /**
     * 內部構建器,通過構建器例項化類
     */
    public static class Bulider{

        private final String name;

        private  int age;

        private  int height;

        private int weight;

        public Bulider(String name){
            this.name = name;
        }

        public Bulider setAge(int age){
            this.age = age;
            return this;
        }

        public Bulider setHeight(int height){
            this.height = height;
            return this;
        }

        public Bulider setWeight(int weight){
            this.weight = weight;
            return this;
        }

        public Service bulider(){
            return new Service(this);
        }

    }

    public String toString(){
        return "name:"+name+" age:"+age+" height:"+height+" weight:"+weight;
    }

    private Service(Bulider bulider){
        this.name = bulider.name;
        this.age = bulider.age;
        this.height = bulider.height;
        this.weight = bulider.weight;
    }

    public static void main(String[] args){
        Service service = new Bulider("張三")
                .setAge(10).setHeight(170).setWeight(120).bulider();
        System.out.println(service.toString());
    }

}