Effective Java 2.0_中英文對照_Item 1

文章作者:Tyan
博客:noahsnail.com

Chapter 2 Creating and Destroying Objects

THIS chapter concerns creating and destroying objects: when and how to create them, when and how to avoid creating them, how to ensure they are destroyed in a timely manner, and how to manage any cleanup actions that must precede their destruction.

這章是關于創建和銷毀對象的:什么時候怎樣創建它們,什么時候怎樣避免創建它們,怎樣確保它們被及時的銷毀,怎么管理任何清理操作,清理操作必須在對象銷毀之前。

Item 1: Consider static factory methods instead of constructors

Item 1: 考慮用靜態工廠方法代替構造函數

The normal way for a class to allow a client to obtain an instance of itself is to provide a public constructor. There is another technique that should be a part of every programmer’s toolkit. A class can provide a public static factory method, which is simply a static method that returns an instance of the class. Here’s a simple example from Boolean (the boxed primitive class for the primitive type boolean). This method translates a boolean primitive value into a Boolean object reference:

一個類允許客戶獲得它本身的一個實例通常的方式是提供一個公有的構造函數。還有另一種技術應該成為每個程序員工具箱中的一部分。一個類可以提供一種公有的static factory methodstatic factory method是一種簡單的靜態方法,它會返回一個類的實例。這有一個來自Boolean(基本類型boolean的封裝類)的簡單例子。這個方法將一個布爾值轉成Boolean對象的引用:

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

Note that a static factory method is not the same as the Factory Method pattern from Design Patterns [Gamma95, p. 107]. The static factory method described in this item has no direct equivalent in Design Patterns.

注意靜態工廠方法與Design Patterns中的Factory Method是不同的。這個條目中描述的靜態工廠方法與設計模式中的工廠方法是不等價的。

A class can provide its clients with static factory methods instead of, or in addition to, constructors. Providing a static factory method instead of a public constructor has both advantages and disadvantages.

一個類可以為它的客戶提供靜態工廠方法來代替構造函數,或者除了構造函數之外再提供一個靜態工廠方法。提供靜態工廠方法代替公有構造函數既有優點也有缺點。

One advantage of static factory methods is that, unlike constructors, they have names. If the parameters to a constructor do not, in and of themselves, describe the object being returned, a static factory with a well-chosen name is easier to use and the resulting client code easier to read. For example, the constructor BigInteger(int, int, Random), which returns a BigInteger that is probably prime, would have been better expressed as a static factory method named BigInteger.probablePrime. (This method was eventually added in the 1.4 release.)

與構造函數相比,靜態工廠方法的第一個優勢是它們有名字。如果構造函數的參數本身不能描述返回的對象,具有合適名字的靜態工廠是更容易使用的,并且產生的客戶端代碼更易讀。例如,構造函數BigInteger(int, int, Random)返回一個BigInteger,這個BigInteger可能是一個素數,使用名字為BigInteger.probablePrime的靜態工廠方法來表示會更好。(這個方法最終在1.4版本被引入。)

A class can have only a single constructor with a given signature. Programmers have been known to get around this restriction by providing two constructors whose parameter lists differ only in the order of their parameter types. This is a really bad idea. The user of such an API will never be able to remember which constructor is which and will end up calling the wrong one by mistake. People reading code that uses these constructors will not know what the code does without referring to the class documentation.

一個類只能有一個具有指定簽名的構造函數。程序員知道怎樣規避這個限制:通過提供兩個構造函數,它們僅在參數列表類型的順序上有所不同。這真的是一個壞主意。使用這種API的用戶永遠不能記住哪一個構造函數是哪一個,最后會無意中調用錯誤的構造函數。使用這些構造函數的人在讀代碼時如果沒有類的參考文檔將不知道代碼要做什么。

Because they have names, static factory methods don’t share the restriction discussed in the previous paragraph. In cases where a class seems to require multiple constructors with the same signature, replace the constructors with static factory methods and carefully chosen names to highlight their differences.

因為靜態工廠方法有名字,因此它們不會有上一段討論的那種限制。當一個類似乎需要多個具有相同簽名的構造函數時,用靜態工廠方法代替構造函數,通過仔細選擇工廠方法的名字來突出它們的不同。

A second advantage of static factory methods is that, unlike constructors, they are not required to create a new object each time they’re invoked. This allows immutable classes (Item 15) to use preconstructed instances, or to cache instances as they’re constructed, and dispense them repeatedly to avoid creating unnecessary duplicate objects. The Boolean.valueOf(boolean) method illustrates this technique: it never creates an object. This technique is similar to the Flyweight pattern [Gamma95, p. 195]. It can greatly improve performance if equivalent objects are requested often, especially if they are expensive to create.

與構造函數相比,靜態工廠方法的第二個優勢是當調用靜態工廠方法時不要求每次都創建一個新的對象。這允許不可變類(Item 15)使用預創建的實例,或緩存構建好的實例,通過重復分發它們避免創建不必要的重復對象。Boolean.valueOf(boolean)方法闡明了這個技術:它從未創建對象。這項技術與Flyweight模式類似[Gamma95, p. 195]。如果經常請求相同的對象,它能極大的提升性能,尤其是在創建對象的代價較昂貴時。

The ability of static factory methods to return the same object from repeated invocations allows classes to maintain strict control over what instances exist at any time. Classes that do this are said to be instance-controlled. There are several reasons to write instance-controlled classes. Instance control allows a class to guarantee that it is a singleton (Item 3) or noninstantiable (Item 4). Also, it allows an immutable class (Item 15) to make the guarantee that no two equal instances exist: a.equals(b) if and only if a==b. If a class makes this guarantee, then its clients can use the == operator instead of the equals(Object) method, which may result in improved performance. Enum types (Item 30) provide this guarantee.

靜態工廠方法能從重復的調用中返回相同的對象,在任何時候都能使類嚴格控制存在的實例。這些類被稱為控制實例。編寫控制實例類是有一些原因的。實例控制允許一個類保證它是一個單例(Item 3)或不可實例化的(Item 4)。它也允許一個不變的類(Item 15)保證不存在兩個相等的實例:a.equals(b)當且僅當a==b。如果一個類保證了這一點,它的客戶端可以使用==操作符代替equals(Object)方法,這可能會導致性能的提升。Enum類型(Item 30)保證了這一點。

A third advantage of static factory methods is that, unlike constructors, they can return an object of any subtype of their return type. This gives you great flexibility in choosing the class of the returned object.

與構造函數相比,靜態工廠方法的第三個優勢是它們能返回它們的返回類型的任意子類型的對象。這樣在選擇返回對象的類時有了更大的靈活性。

One application of this flexibility is that an API can return objects without making their classes public. Hiding implementation classes in this fashion leads to a very compact API. This technique lends itself to interface-based frameworks (Item 18), where interfaces provide natural return types for static factory methods.Interfaces can’t have static methods, so by convention, static factory methods for an interface named Type are put in a noninstantiable class (Item 4) named Types.

靈活性的一個應用是API能返回對象而不必使它們的類變成公有的。通過這種方式中隱藏實現類會有一個更簡潔的API。這項技術適用于基于接口的框架(Item 18),接口為靜態工廠方法提供了自然的返回類型。接口不能有靜態方法,因此按慣例,命名為Type的接口的靜態工廠方法被放在一個命名為Types的不可實例化的類中(Item 4)。

For example, the Java Collections Framework has thirty-two convenience implementations of its collection interfaces, providing unmodifiable collections, synchronized collections, and the like. Nearly all of these implementations are exported via static factory methods in one noninstantiable class (java.util.Collections). The classes of the returned objects are all nonpublic.

例如,Java集合框架有三十二個集合接口的便利實現,提供了不可修改的集合,同步集合等等。幾乎所有的這些實現都是通過靜態工廠方法導出在一個不可實例化的類中(java.util.Collections)。返回對象的類都是非公有的。

The Collections Framework API is much smaller than it would have been had it exported thirty-two separate public classes, one for each convenience implementation. It is not just the bulk of the API that is reduced, but the conceptual weight. The user knows that the returned object has precisely the API specified by its interface, so there is no need to read additional class documentation for the implementation classes. Furthermore, using such a static factory method requires the client to refer to the returned object by its interface rather than its implementation class, which is generally good practice (Item 52).

集合框架API比它導出的三十二個分開的公有類更小,每一個便利實現對應一個類。它不僅僅是API的數量在減少,還是概念上意義上的減少。用戶知道返回的對象含有接口指定的精確API,因此不需要閱讀額外的實現類的文檔。此外,使用這樣的靜態工廠方法需要客戶端使用接口引用返回的對象而不是使用它的實現類,這通常是最佳的實踐(Item 52)。

Not only can the class of an object returned by a public static factory method be nonpublic, but the class can vary from invocation to invocation depending on the values of the parameters to the static factory. Any class that is a subtype of the declared return type is permissible. The class of the returned object can also vary from release to release for enhanced software maintainability and performance.

不僅公有靜態工廠方法返回對象的類可以是非公有的,而且這個類還可以隨著調用靜態工廠時輸入的參數值的變化而變化。聲明的返回值類型的任何子類都是可以的。為了增強軟件的可維護性及性能,返回值對象的類也可以隨著發布版本的變化而變化。

The class java.util.EnumSet (Item 32), introduced in release 1.5, has no public constructors, only static factories. They return one of two implementations, depending on the size of the underlying enum type: if it has sixty-four or fewer elements, as most enum types do, the static factories return a RegularEnumSet instance, which is backed by a single long; if the enum type has sixty-five or more elements, the factories return a JumboEnumSet instance, backed by a long array.

在1.5版本中引入類java.util.EnumSet(Item 32),它沒有公有的構造函數,只有靜態工廠方法。根據枚舉類型的大小,靜態工廠方法返回兩個實現中的一個,枚舉類型的分類:如果枚舉類型中有六十四個元素或更少,與大多數枚舉類型一樣,靜態工廠返回一個RegularEnumSet實例,由單個的long支持;如果枚舉類型中有六十五個元素或更多,靜態工廠方法返回一個JumboEnumSet實例,由long[]支持。

The existence of these two implementation classes is invisible to clients. If RegularEnumSet ceased to offer performance advantages for small enum types, it could be eliminated from a future release with no ill effects. Similarly, a future release could add a third or fourth implementation of EnumSet if it proved beneficial for performance. Clients neither know nor care about the class of the object they get back from the factory; they care only that it is some subclass of EnumSet.

現有的兩個實現類對于客戶端是不可見的。如果RegularEnumSet對于較少數量的枚舉類型沒有提供性能優勢,那么在將來的版本中將其移除不會任何影響。同樣地,如果新的EnumSet實現在性能上更有優勢,在將來的版本中添加EnumSet的第三或第四個實現也不會有任何影響。客戶端不知道也不關心它們從工廠方法中得到的對象所屬的類;它們只關心它是EnumSet的某個子類。

The class of the object returned by a static factory method need not even exist at the time the class containing the method is written. Such flexible static factory methods form the basis of service provider frameworks, such as the Java Database Connectivity API (JDBC). A service provider framework is a system in which multiple service providers implement a service, and the system makes the implementations available to its clients, decoupling them from the implementations.

在編寫靜態工廠方法所屬的類時,靜態工廠方法返回的對象所屬的類可以不必存在。這種靈活的靜態工廠方法形成了服務提供者框架的基礎,例如Java數據庫鏈接API(JDBC)。服務提供者框架是一個系統:多個服務提供者實現一個服務,系統為客戶端提供服務的多個實現,使客戶端與服務實現解耦。

There are three essential components of a service provider framework: a service interface, which providers implement; a provider registration API, which the system uses to register implementations, giving clients access to them; and a service access API, which clients use to obtain an instance of the service. The service access API typically allows but does not require the client to specify some criteria for choosing a provider. In the absence of such a specification, the API returns an instance of a default implementation. The service access API is the “flexible static factory” that forms the basis of the service provider framework.

服務提供者框架有三個基本的組件:服務接口,提供者實現;提供者注冊API,系統用來注冊實現,使客戶端能訪問它們;服務訪問API,客戶端用來得到服務實例。服務訪問API通常允許但不要求客戶端指定一些選擇提供者的規則。在沒有指定的情況下,API返回一個默認的實現實例。服務訪問API是"靈活的靜態工廠",其形成了服務提供者框架的基礎。

An optional fourth component of a service provider framework is a service provider interface, which providers implement to create instances of their service implementation. In the absence of a service provider interface, implementations are registered by class name and instantiated reflectively (Item 53). In the case of JDBC, Connection plays the part of the service interface, DriverManager.registerDriver is the provider registration API, DriverManager.getConnection is the service access API, and Driver is the service provider interface.

服務提供者框架的第四個可選組件是服務提供者接口,服務提供者通過實現這個接口來創建服務實現的實例。在沒有服務提供者接口的情況下,服務實現通過類名進行注冊,通過反射來進行實例化(Item 53)。在JDBC的案例中,Connection是服務接口,DriverManager.registerDriver是提供者注冊API,DriverManager.getConnection服務訪問API,Driver是服務提供者接口。

There are numerous variants of the service provider framework pattern. For example, the service access API can return a richer service interface than the one required of the provider, using the Adapter pattern [Gamma95, p. 139]. Here is a simple implementation with a service provider interface and a default provider:

服務提供者框架模式有許多變種。例如,服務訪問API通過使用適配器模式[Gamma95, p. 139],能返回比提供者需要的更更豐富的服務接口。下面是服務提供者接口的一個簡單實現和默認的提供者:

    // Service provider framework sketch

    // Service interface
    public interface Service {
        ... // Service-specific methods go here
    }

    // Service provider interface
    public interface Provider {
        Service newService();
    }

    // Noninstantiable class for service registration and access
    public class Services {
        private Services() { }  // Prevents instantiation (Item 4)

        // Maps service names to services
        private static final Map<String, Provider> providers =
            new ConcurrentHashMap<String, Provider>();

        public static final String DEFAULT_PROVIDER_NAME = "<def>";

        // Provider registration API
        public static void registerDefaultProvider(Provider p) {
            registerProvider(DEFAULT_PROVIDER_NAME, p);
        }

        public static void registerProvider(String name, Provider p){
            providers.put(name, p);
        }

        // Service access API
        public static Service newInstance() {
            return newInstance(DEFAULT_PROVIDER_NAME);
        }
        
        public static Service newInstance(String name) {
            Provider p = providers.get(name);
            if (p == null)
                throw new IllegalArgumentException(
                    "No provider registered with name: " + name);
        return p.newService();
        }
    }

A fourth advantage of static factory methods is that they reduce the verbosity of creating parameterized type instances. Unfortunately, you must specify the type parameters when you invoke the constructor of a parameterized class even if they’re obvious from context. This typically requires you to provide the type parameters twice in quick succession:

靜態工廠方法的第四個優勢是它們降低了創建參數化類型實例的冗長性。遺憾的是,當你調用參數化類的構造函數時,你必須指定類型參數,即使它們在上下文中是非常明顯的。這通常需要你緊接著提供兩次類型參數:

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

This redundant specification quickly becomes painful as the length and complexity of the type parameters increase. With static factories, however, the compiler can figure out the type parameters for you. This is known as type inference. For example, suppose that HashMap provided this static factory:

隨著類型參數長度和復雜性的增加,這個冗長的說明很快就讓人變得很痛苦。但是使用靜態工廠的話,編譯器可以為你找出類型參數。這被稱為類型推導。例如,假設HashMap由這個靜態工廠提供:

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

Then you could replace the wordy declaration above with this succinct alternative:

你可以將上面冗長的聲明用下面簡潔的形式去替換:

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

Someday the language may perform this sort of type inference on constructor invocations as well as method invocations, but as of release 1.6, it does not.

某一天,Java語言可能在構造函數調用上也有與方法調用類似的類型推導,但到發行版本1.6為止,它一直沒有。

Unfortunately, the standard collection implementations such as HashMap do not have factory methods as of release 1.6, but you can put these methods in your own utility class. More importantly, you can provide such static factories in your own parameterized classes.

遺憾的是,但到發行版本1.6為止,標準集合實現例如HashMap沒有工廠方法,但你可以把這些方法放到你自己的工具類力。更重要的是,你可以在你自己的參數化類里提供這樣的靜態工廠。

The main disadvantage of providing only static factory methods is that classes without public or protected constructors cannot be subclassed. The same is true for nonpublic classes returned by public static factories. For example, it is impossible to subclass any of the convenience implementation classes in the Collections Framework. Arguably this can be a blessing in disguise, as it encourages programmers to use composition instead of inheritance (Item 16).

只提供靜態工廠方法的主要缺點是沒有公有或保護構造函數的類不能進行子類化。公有靜態工廠返回的非公有類同樣如此。例如,不可能子類化集合框架中的這些便利實現類。可以說這是因禍得福,因為它鼓勵程序員使用組合來代替繼承(Item 16)。

A second disadvantage of static factory methods is that they are not readily distinguishable from other static methods. They do not stand out in API documentation in the way that constructors do, so it can be difficult to figure out how to instantiate a class that provides static factory methods instead of constructors. The Javadoc tool may someday draw attention to static factory methods. In the meantime, you can reduce this disadvantage by drawing attention to static factories in class or interface comments, and by adhering to common naming conventions. Here are some common names for static factory methods:

  • valueOf — Returns an instance that has, loosely speaking, the same value as its parameters. Such static factories are effectively type-conversion methods.

  • of — A concise alternative to valueOf, popularized by EnumSet (Item 32).

  • getInstance — Returns an instance that is described by the parameters but cannot be said to have the same value. In the case of a singleton, getInstance takes no parameters and returns the sole instance.

  • newInstance — Like getInstance, except that newInstance guarantees that each instance returned is distinct from all others.

  • getType — Like getInstance, but used when the factory method is in a different class. Type indicates the type of object returned by the factory method.

  • newType — Like newInstance, but used when the factory method is in a different class. Type indicates the type of object returned by the factory method.

靜態工廠方法的第二個缺點是它們不能很容易的與其它靜態方法進行區分。它們不能像構造函數那樣在API文檔中明確標識出來,因此很難弄明白怎樣實例化一個提供靜態工廠方法代替構造函數的類。Javadoc工具可能某一天會關注靜態工廠方法。同時,你可以通過在類中或接口注釋中注意靜態工廠和遵循通用命名約定來減少這個劣勢。下面是靜態工廠方法的一些常用命名:

  • valueOf — 不嚴格地說,返回一個與它的參數值相同的一個實例。這種靜態工廠是有效的類型轉換方法。

  • ofvalueOf的一種簡潔替代方法,通過EnumSet(Item 32)得到普及。

  • getInstance — 返回一個通過參數描述的實例,但不能說是相同的值。在單例情況下,getInstance沒有參數并且返回唯一的一個實例。

  • newInstance — 除了newInstance保證每個返回的實例都是與其它的實例不同之外,其它的類似于getInstance

  • getType — 類似于getInstance,當靜態工廠方法在不同的類中時使用。Type表示靜態工廠方法返回的對象類型。

  • newType — 類似于newInstance,當靜態工廠方法在不同的類中時使用。Type表示靜態工廠方法返回的對象類型。

In summary, static factory methods and public constructors both have their uses, and it pays to understand their relative merits. Often static factories are preferable, so avoid the reflex to provide public constructors without first considering static factories.

總之,靜態工廠方法和公有構造函數都有它們的作用,理解它們的相對優勢是值得的。靜態工廠經常是更合適的,因此要避免習慣性的提供公有構造函數而不首先考慮靜態工廠。

總結:

1.靜態工廠的優點:

  • 與構造函數相比,靜態工廠方法的第一個優勢是它們有名字。

  • 與構造函數相比,靜態工廠方法的第二個優勢是當調用靜態工廠方法時不要求每次都創建一個新的對象。

  • 與構造函數相比,靜態工廠方法的第三個優勢是它們能返回它們的返回類型的任意子類型的對象。

  • 靜態工廠方法的第四個優勢是它們降低了創建參數化類型實例的冗長性。

2.靜態工廠的缺點:

  • 只提供靜態工廠方法的主要缺點是沒有公有或保護構造函數的類不能進行子類化。

  • 靜態工廠方法的第二個缺點是它們不能很容易的與其它靜態方法進行區分。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,501評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,673評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,610評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,939評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,668評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,004評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,001評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,173評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,705評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,426評論 3 359
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,656評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,139評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,833評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,247評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,580評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,371評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,621評論 2 380

推薦閱讀更多精彩內容