如果你没有一颗最求完善的心,得过且过,请远离设计模式。 如果你不知道设计原则,请远离设计模式。 如果你为了学习设计模式而学习设计模式,又不是太需要设计模式,请远离设计模式。
单例模式:
保证一个类仅有一个实例,并提供一个访问他的全局访问点
?--什么样的对象适合用单例?
|--一个对象足以完成任务时,没有必要去创建多个对象
|--一个对象非常消耗资源,需要限制对象的创建
比如:世界,你不会让别人随便去new,如何不让外部无法创建本类对象, 如何给外部提供唯一的对象,是单例模式的核心,要达到这两点很简单。
形式上的一切都仅是开始而已
即便无人问津,我也永远存在
饿汉式.png
public class World {
private static World sWorld = new World();
//[1]私有化构造
private World() {
initWorld();//初始化世界
System.out.println("世界已创建");
}
private void initWorld() {
}
//[2]返回内部静态实例
public static World getInstance() {
return sWorld;
}
}
虽然我们不是同类,但感谢有你相伴
懒汉双检锁.png
public class World {
private static volatile World sWorld;
//[1]私有化构造
private World() {
initWorld();//初始化世界
System.out.println("世界已创建");
}
private void initWorld() {
}
//[2]返回内部静态实例
public static World getInstance() {
if (sWorld == null) {//判断非空后--执行
synchronized (World.class) {//加锁,保证多线程下的单例
if (sWorld == null) {//非空,创建实例
sWorld = new World();
}
}
}
return sWorld;
}
}
和上面的功能基本一致,所以我喜欢这个
静态内部类.png
public class World {
//[1]私有化构造
private World() {
initWorld();//初始化世界
System.out.println("世界已创建");
}
private void initWorld() {
}
//[3]返回内部静态实例
public static World getInstance() {
return WorldHolder.sWorld;
}
//[2]创建内部类创建实例
private static class WorldHolder {
private static final World sWorld = new World();
}
}
枚举.png
public enum World {
INSTANCE;
World() {
initWorld();//初始化世界
System.out.println("世界已创建");
}
private void initWorld() {
}
}
单例的价值在于一个程序中只用一个该对象实例 如果有恶意份子通过反射创建了另一个世界会怎么样?
通过debug看出两次获取的都是同一个世界,这就是单一实例
单例测试.png
public class God {
public static void main(String[] args) {
World world1 = World.getInstance();
World world2 = World.getInstance();
}
}
可见
world3
的内存地址已经不一样了,说明出现了第二个世界,也就是单例的失效 不过应该没有人吃饱了没事干用反射创建单例对象吧,天堂有路你不走...
反射测试.png
public class God {
public static void main(String[] args) {
World world1 = World.getInstance();
World world2 = World.getInstance();
//通过反射创建
Class<World> worldClass = World.class;
try {
Constructor<World> constructor = worldClass.getDeclaredConstructor(null);
constructor.setAccessible(true);
World world3 = constructor.newInstance();
System.out.println(world3==world2);//false
System.out.println(world1==world2);//true
} catch (Exception e) {
e.printStackTrace();
}
}
}
如果你的单例类有序列化的需求(如,单例对象本地存储,单例对象网络传输) 反序列化形成的实例也并非原来的实例
反序列化.png
---->[World]-------------
public class World implements Serializable {
---->[God]-------------
public class God {
public static void main(String[] args) {
World world1 = World.getInstance();
World world2 = World.getInstance();
//通过反射创建
Class<World> worldClass = World.class;
try {
Constructor<World> constructor = worldClass.getDeclaredConstructor(null);
constructor.setAccessible(true);
World world3 = constructor.newInstance();
System.out.println(world3 == world2);//false
System.out.println(world1 == world2);//true
} catch (Exception e) {
e.printStackTrace();
}
//通过反序列化创建对象
try {
//序列化输出
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("world.obj"));
oos.writeObject(world1);
//反序列化创建对象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("world.obj"));
World world4 = (World) ois.readObject();
ois.close();
System.out.println(world1 == world4);//false
} catch (Exception e) {
e.printStackTrace();
}
}
}
通过反序列化时的钩子函数:
readResolve
来控制序列化对象实例
反序列化的防治.png
---->[World]-------------
//解决反序列化创建实例的问题,readResolve创建的对象会直接替换io流读取的对象
private Object readResolve() throws ObjectStreamException {
return getInstance();
}
优点:
设计者严格管控这个类,全局作用。简化使用者使用
只创建一个实例,避免频繁创建销毁对象,节省内存资源,减少系统开销
缺点:
没有抽象层,不利于扩展
职责过重,违背单一职责原则
java.util.Calendar 标准单例,通过Calendar.getInstance方法获取对象
java.lang.System 完全单例,不提供外部构造方法,全部以静态方法提供服务
android.view.LayoutInflater 标准单例 ,通过LayoutInflater.from(Context)方法获取对象
项目源码 | 日期 | 附录 |
---|---|---|
V0.1--github | 2018-2-10 | 无 |
发布名:
设计模式1:创建型-单例模式
捷文链接:https://cloud.tencent.com/developer/article/1397732
笔名 | 微信 | |
---|---|---|
张风捷特烈 | 1981462002 | zdl1994328 |
我的github:https://github.com/toly1994328 我的简书:https://www.jianshu.com/u/e4e52c116681 我的掘金:https://juejin.im/user/5b42c0656fb9a04fe727eb37 个人网站:http://www.toly1994.com
1----本文由张风捷特烈原创,转载请注明 2----欢迎广大编程爱好者共同交流 3----个人能力有限,如有不正之处欢迎大家批评指证,必定虚心改正 4----看到这里,我在此感谢你的喜欢与支持