第3条:使用私有构造器或者枚举类型来强化Singleton属性

 

Singleton通常被用来表示一个无状态的对象,比如函数(条目24),或者一个独一无二的系统组建。使类成为Singleton会使得它的客户端难以调试,因为无法用模拟实现去替代Singleton,除非这个类实现一个充当其类型的接口
实现Singleton有两种方法,两种方法都要把构造器私有化

有两种通用的方式来实现Singleton。但这两种方式都是将构造器私有化,然后提供一个公有的静态成员,并通过这个静态成员来访问这个唯一的实例。在第一种方式中,这个静态成员是final属性:

1   public class Elvis{
2     public static final Elvis INSTANCE=new Elvis();
3     private Elvis(){}
4     public void leavetThebuilding(){...}
5     }

 

私有构造器仅被调用一次,缺少公有或受保护的构造器,保证了全局唯一性,一旦被实例化,只会存在一个Elvis实例,但是客户端可以利用反射 AcccessilblObject.setAccessilble方法调用私有构造器.
如需要抵抗这种攻击,可以修改构造器,他被要求创建第二个实例的时候抛出异常

实现Singleton的第二种方法

1   public class Elvis{
2     private static final Elvis INSTANCE=new Elvis();
3     private Elvis(){}
4     public static Elvis getInstance(){ return    INSTANCE;}
5     public void leavetThebuilding(){...}
6     }

采用第一种方式的好处是,透过API,我们能清晰地意识到这个类是个Singleton:公有静态属性是final不可变的,所以它将总是保持着相同的对象引用。而第二种方式的好处是它更简单些
采用静态工厂的方式的另一个好处是,在不改变API的前提下,若想改变该类是否为Singleton的想法,它给了我们灵活性
采用静态工厂的方式的另一个好处是,在不改变API的前提下,若想改变该类是否为Singleton的想法,它给了我们灵活性。
工厂方法返回了唯一的实例,但我们也可以对其进行修改,比如改成对每个调用它的线程返回一个唯一实例。
还一个好处是,如果应用有需求,我们可以写一个通用的Singleton工厂
最后还有一个好处,就是静态工厂方法引用能作为一个Supplier,例如,Elvis:instance就是一个Supplier<Elvis>
除非上述这些优点的任一一个是很重要的,否则公有属性方式(即第一种方式)是更可取的。

考虑到序列化的情况,每次反序列化一个序列化实例时,都会创建一个新的实例,为反正这种情况需要在Elvis 类中加入readResolve方法

public Object readResolve(){ 
return INSTANCE; 
}

  

3 枚举方式

public enum Elvis { 
INSTANCE; 
public void leavetThebuilding(){…} 
}

  

posted @ 2017-09-28 15:59  webzom  阅读(103)  评论(0)    收藏  举报