所谓Singleton,是指仅能被实例化一次的类。Singleton通常代表本质上唯一的系统组件,例如窗口管理器或文件系统。让一个类成为Singleton就无法为Singleton替换模拟实现,除非它实现一个作为其类型的接口,所以会让其客户端难于测试。
JDK1.5之前,有两种方法可以实现Singleton,二者均基于让构造函数私有化,并导出一个公共静态成员来提供对唯一实例的访问。在方法一中,该公共静态成员是一个final域:
//Singleton with public final field
public class Elvis{
public static final Elvis INSTANCE = new Elvis();
private Elvis(){...}
public void leaveTheBuilding(){...}
}
这里私有的构造函数仅被调用一次,用来初始化公共静态final域Elvis.INSTANCE。由于未提供public或protected的构造函数,所以保证了Elvis的全局唯一:一旦Elvis类被实例化,就只会存在唯一的一个Elvis实例,不多也不少。客户端的任何行为都改变不了这一点,
不过要提醒一点:享有特权的客户端可以借助AccessibleObject.setAccessible()方法,通过反射(Item53)调用private构造函数。如果你需要防止这种攻击,则修改构造函数,当它被调用来创建第二个实例时抛出一个异常。
在实现Singleton的方法二中,该公共静态成员是一个静态工厂方法:
//Singleton with static factory
public class Elvis{
private static final Elvis INSTANCE = new Elvis();
private Elvis(){...}
public static Elvis getInstance(){
return INSTANCE;
}
public void leaveTheBuilding(){...}
}
对Elvis.getInstance()的所有调用都返回相同的对象引用,不会创建任何其他的Elvis实例。(上文的提醒也要关注)。
public域方法(方法一)的主要优点是,类声明清楚地表明该类是Singleton:公共的静态域是final的,所以该域总是包含相同的对象引用。public域方法的性能优势已不存在了:现代的java虚拟机实现差不多都将其调用内联到静态工厂方法。
工厂方法(方法二)的一个优点是,你可以灵活地决定是否将类设为Singleton,而不用改变其API。例如,返回唯一实例的工厂方法,可以很容易地改为为每个调用它的线程返回一个唯一实例。第二个优点和Item27所讨论的泛型有关。通常这些优势都不相关,而且静态域方法更简单。
为了将使用上述方法的Singleton类变为可序列化,单单增加implements Serializable是不够的。为了维持Singleton的保证,你还需要将所有实例变量声明为transient,并提供readResolve方法*(Item77)。否则,每次实例反序列化时,都会创建一个新的实例。在上例中就会导致“假冒的Elvis”,为了防止这种情况,需要在Elvis类中增加readResolve方法:
//readResolve method to preserve singleton property
private Object readResolve(){
//return the one true Elvis and let the garbage collector take care of the Elvis impersonator
return INSTANCE;
}
JDK1.5之后,还有
第三种方法来实现Singleton,只要简单地编写一个只包含一个元素的枚举类型:
//Enum singletion - the preferred approach
public enum Elvis{
INSTANCE;
public void leaveTheBuilding(){...}
}
该方法与公共域方法类似,不过它更加简洁,无偿提供序列化机制,并且绝对保证不会被多次实例化,即使是在面对复杂的序列化或反射攻击的时候也这样。虽然这种方法尚未被广泛采用,但
单元素的枚举类型是实现Singleton的最佳方式。
#######################################
关于readResolve():
JDK API描述:
将对象写入流时需要指定要使用的替代对象的可序列化类,应使用准确的签名来实现此特殊方法:
ANY-ACCESS-MODIFIER Object writeReplace() throws ObjectStreamException;
在从流中读取类的一个实例时需要指定替代的类,应使用的准确签名来实现此特殊方法。
ANY-ACCESS-MODIFIER Object readResolve() throws ObjectStreamException;
此 writeReplace、readResolve 方法将由序列化调用,前提是如果此方法存在,而且它可以通过被序列化对象的类中定义的一个方法访问。因此,该方法可以拥有私有 (private)、受保护的 (protected) 和包私有 (package-private) 访问。子类对此方法的访问遵循 java 访问规则。
也就是说,
writeReplace()方法返回的对象,就是要被序列化的对象,我们有机会在序列化前把这个对象给换成我们确定好的那个(貌似没什么用处);
readResolve()方法就是在反序列化完成得到对象前,把这个对象给换成我们确定好的那个。
为了防止有人恶意通过序列化的机制破坏定义好的单例,就需要自己实现readResolve()方法,把单例定义的唯一实现在这个方法中返回。
分享到:
相关推荐
3: 3_Params-Validate 4: 4_Class-Singleton 5: 5_DateTime-TimeZone 6: 6_DateTime-Locale 7: 7_DateTime 8: 8_AppConfig 9: 9_Template-Toolkit 10: 10_Email-Address 11: 11_Email-Simple 12: 12_Return-Value 13...
Singleton拥有一个私有构造函数,确保用户无法通过new直接实例化它。除此之外,该模式中包含一个静态私有成员变量instance与静态公有方法Instance()。Instance()方法负责检验并实例化自己,然后存储在静态成员变量中...
李建忠面向对象设计模式视频精讲:Singleton 单件(创建型模式)
3、有构造函数,构造函数有没有参数版本(DEFINE_SINGLETON_CONSTRUCT_WITH_DEFAULT); 4、有构造函数,构造函数都有参数(DEFINE_SINGLETON_CONSTRUCT); 通过宏定义巧妙实现,使用也很方便!
Item 3: Enforce the singleton property with a private constructor or an enum type Item 4: Enforce noninstantiability with a private constructor Item 5: Prefer dependency injection to hardwiring ...
参考文档:电梯直达 ... /// 私有构造函数 EventBus._internal(); /// 保存单例 static EventBus _singleton = new EventBus._internal(); /// 工厂构造函数 factory EventBus() => _singleton; /// 保
class Singleton(object): def __new__(cls, *args, **kwargs): if not hasattr(cls, 'instance'): cls.instance = super(Singleton, cls).__new__(cls) return cls.instance class MyClass(Singleton): ...
文件名 : Singleton3.java 文件名 : Singleton4.java 文件名 : Singleton5.java 文件名 : Singleton6.java 文件名 : TestSingleton1.java 文件名 : TestSingleton2.java 文件名 : TestSingleton3.java 文件名...
C#面向对象设计模式纵横谈(2):Singleton 单件(创建型模式)
:grinning_face:点击查看电子书,体验更好 :backhand_index_pointing_right: 创建型 (Creational)Java Kotlin结构型(Structural)适配器模式(Adapter Class/Object Pattern) Java桥接模式(Bridge Pattern) ...
此外通过在应用启动/中止时进行对象自动的预先创建/销毁,使这个模式能够用来替代静态对象的创建/销毁。例子单例(singleton)是一种通用的创建模式,它对唯一的类实例提供了一个全局的访问点同时能够延迟实例的创建...
常规Java工具,算法,加密,数据库,面试题,源代码分析,解决方案: Alibaba_Druid AngularJS_String_SubString Big_Data_ETL C# CROS CrossOrigin_Request Eclipse_Referenced_File_Contains_Errors Git_Language_...
1:Python如何实现单例模式? Python有两种方式可以实现单例模式,下面两个例子使用了不同的方式实现单例模式:... 使用decorator来实现单例模式 def singleton(cls): instances = {} def getinstance(): if cls not in
设计模式之单例模式。Java代码实现。五种实现方式
简单的单例模式举例Singleton 分为恶汉式 懒汉式
超市收银管理系统java源码 官方网站: 100 字 Java 中的 GoF 设计模式 介绍 想法:以简单的方式描述 GoF 设计模式。 每个模式将使用以下结构进行描述: 故事(100字以内) 在 Java 中的实现 GoF 设计模式 创造模式 ...
C#面向对象设计模式纵横谈(2):Singleton 单件(创建型模式) (Level 300)
java设计模式,单例模式的不同实现方式
非单例的对象是在调用getBean()方法时才创建对象,在同一个bean获取的资源时,用getBean()方法得到的对象都不相同 request、session、application、websocket:设定创建出的对象放置在web容器对应的位置 三、...