时间:2021-05-21
单例模式 Singleton 简单实例设计模式解析
前言
今天我来全面总结一下Android开发中最常用的设计模式 - 单例模式。
关于设计模式的介绍,可以看下我之前写的:1分钟全面了解“设计模式”
目录
1. 引入
1.1 解决的是什么问题
之前说过,设计模式 = 某类特定问题的解决方案,那么单例模式是解决什么问题的解决方案呢?
含义:单例 =一个实例;
解决的问题:降低对象之间的耦合度
解决方法:单例模式,即实现一个类只有一个实例化对象,并提供一个全局访问点
1.2 实例引入
接下来我用一个实例来对单例模式进行引入
背景:小成有一个塑料生产厂,但里面只有一个仓库。
目的:想用代码来实现仓库的管理
现有做法: 建立仓库类和工人类
其中,仓库类里的quantity=商品数量;工人类里有搬运方法MoveIn(int i)和MoveOut(int i)。
出现的问题:通过测试发现,每次工人搬运操作都会新建一个仓库,就是货物都不是放在同一仓库,这是怎么回事呢?(看下面代码)
package scut.designmodel.SingletonPattern;//仓库类class StoreHouse { private int quantity = 100; public void setQuantity(int quantity) { this.quantity = quantity; } public int getQuantity() { return quantity; }}//搬货工人类class Carrier{ public StoreHouse mStoreHouse; public Carrier(StoreHouse storeHouse){ mStoreHouse = storeHouse; } //搬货进仓库 public void MoveIn(int i){ mStoreHouse.setQuantity(mStoreHouse.getQuantity()+i); } //搬货出仓库 public void MoveOut(int i){ mStoreHouse.setQuantity(mStoreHouse.getQuantity()-i); }}//工人搬运测试public class SinglePattern { public static void main(String[] args){ StoreHouse mStoreHouse1 = new StoreHouse(); StoreHouse mStoreHouse2 = new StoreHouse(); Carrier Carrier1 = new Carrier(mStoreHouse1); Carrier Carrier2 = new Carrier(mStoreHouse2); System.out.println("两个是不是同一个?"); if(mStoreHouse1.equals(mStoreHouse2)){//这里用equals而不是用 == 符号,因为 == 符号只是比较两个对象的地址 System.out.println("是同一个"); }else { System.out.println("不是同一个"); } //搬运工搬完货物之后出来汇报仓库商品数量 Carrier1.MoveIn(30); System.out.println("仓库商品余量:"+Carrier1.mStoreHouse.getQuantity()); Carrier2.MoveOut(50); System.out.println("仓库商品余量:"+Carrier2.mStoreHouse.getQuantity()); }}结果:
两个是不是同一个?不是同一个仓库商品余量:130仓库商品余量:502. 单例模式介绍
2.1 解决的问题(应用场景)
冲突:从上面的结果可以看出,工人类操作的明显不是同一个仓库实例。
目标:全部工人操作的是同一个仓库实例
单例模式就是为了解决这类问题的解决方案:实现一个类只有一个实例化对象,并提供一个全局访问点2.2 工作原理
在Java中,我们通过使用对象(类实例化后)来操作这些类,类实例化是通过它的构造方法进行的,要是想实现一个类只有一个实例化对象,就要对类的构造方法下功夫:
单例模式的一般实现:(含使用步骤)
public class Singleton {//1. 创建私有变量 ourInstance(用以记录 Singleton 的唯一实例)//2. 内部进行实例化 private static Singleton ourInstance = new Singleton();//3. 把类的构造方法私有化,不让外部调用构造方法实例化 private Singleton() { }//4. 定义公有方法提供该类的全局唯一访问点//5. 外部通过调用getInstance()方法来返回唯一的实例 public static Singleton newInstance() { return ourInstance; }}好了,单例模式的介绍和原理应该了解了吧?那么我们现在来解决上面小成出现的“仓库不是一个”的问题吧!
2.3 实例介绍
小成使用单例模式改善上面例子的代码:
package scut.designmodel.SingletonPattern;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;//单例仓库类class StoreHouse { //仓库商品数量 private int quantity = 100; //自己在内部实例化 private static StoreHouse ourInstance = new StoreHouse();; //让外部通过调用getInstance()方法来返回唯一的实例。 public static StoreHouse getInstance() { return ourInstance; } //封闭构造函数 private StoreHouse() { } public void setQuantity(int quantity) { this.quantity = quantity; } public int getQuantity() { return quantity; }}//搬货工人类class Carrier{ public StoreHouse mStoreHouse; public Carrier(StoreHouse storeHouse){ mStoreHouse = storeHouse; } //搬货进仓库 public void MoveIn(int i){ mStoreHouse.setQuantity(mStoreHouse.getQuantity()+i); } //搬货出仓库 public void MoveOut(int i){ mStoreHouse.setQuantity(mStoreHouse.getQuantity()-i); }}//工人搬运测试public class SinglePattern { public static void main(String[] args){ StoreHouse mStoreHouse1 = StoreHouse.getInstance(); StoreHouse mStoreHouse2 = StoreHouse.getInstance(); Carrier Carrier1 = new Carrier(mStoreHouse1); Carrier Carrier2 = new Carrier(mStoreHouse2); System.out.println("两个是不是同一个?"); if(mStoreHouse1.equals(mStoreHouse2)){ System.out.println("是同一个"); }else { System.out.println("不是同一个"); } //搬运工搬完货物之后出来汇报仓库商品数量 Carrier1.MoveIn(30); System.out.println("仓库商品余量:"+Carrier1.mStoreHouse.getQuantity()); Carrier2.MoveOut(50); System.out.println("仓库商品余量:"+Carrier2.mStoreHouse.getQuantity()); }}结果:
两个是不是同一个?是同一个仓库商品余量:130仓库商品余量:80从结果分析,使用了单例模式后,仓库类就只有一个仓库实例了,再也不用担心搬运工人进错仓库了!!!
2.4 优点
2.5 缺点
3. 单例模式的实现方式
3.1 一般情况
饿汉式(最简单的单例实现方式)
class Singleton { private static Singleton ourInstance = new Singleton(); private Singleton() { } public static Singleton newInstance() { return ourInstance; }}应用场景:
懒汉式
懒汉式与饿汉式最大的区别是单例的初始化操作的时机:
应用场景:
3.2 多线程下的单例模式实现
在多线程的情况下:
解决方案1:同步锁
使用同步锁 synchronized (Singleton.class) 防止多线程同时进入造成instance被多次实例化。
class Singleton { private static Singleton ourInstance = null; private Singleton() { } public static Singleton newInstance() { synchronized (Singleton.class){ if( ourInstance == null){ ourInstance = new Singleton(); } } return ourInstance; }}解决方案2:双重校验锁
在同步锁的基础上( synchronized (Singleton.class) 外)添加了一层if,这是为了在Instance已经实例化后下次进入不必执行 synchronized (Singleton.class) 获取对象锁,从而提高性能。
class Singleton { private static Singleton ourInstance = null; private Singleton() { } public static Singleton newInstance() {if( ourInstance == null){ synchronized (Singleton.class){ if( ourInstance == null){ ourInstance = new Singleton(); } } } return ourInstance; }}解决方案3:静态内部类
在JVM进行类加载的时候会保证数据是同步的,我们采用内部类实现:在内部类里面去创建对象实例。
只要应用中不使用内部类 JVM 就不会去加载这个单例类,也就不会创建单例对象,从而实现“懒汉式”的延迟加载和线程安全。
解决方案4:枚举类型
最简洁、易用的单例实现方式,(《Effective Java》推荐)
public enum Singleton{ //定义一个枚举的元素,它就是Singleton的一个实例 instance; public void doSomething(){ } }使用方式如下:
Singleton singleton = Singleton.instance;singleton.doSomething();5. 总结
本文主要对单例模式进行了全面介绍,包括原理和实现方式,接下来我会继续讲解其他设计模式,有兴趣可以继续关注
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!
声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。
java设计模式--单例模式单例设计模式Singleton是一种创建型模式,指某个类采用Singleton模式,则在这个类被创建后,只可能产生一个实例供外部访问
单例:Singleton,是指仅仅被实例化一次的类。饿汉单例设计模式一、饿汉设计模式publicclassSingletonHungry{privatefina
单例模式(Singleton)也叫单态模式,是设计模式中最为简单的一种模式,甚至有些模式大师都不称其为模式,称其为一种实现技巧,因为设计模式讲究对象之间的关系的
单例(Singleton)模式和不常见的多例(Multiton)模式控制着应用程序中类的数量。如模式名称,单例只能实例化一次,只有一个对象,多例模式可以多次实例
前言大家都知道关于Java中单例(Singleton)模式是一种广泛使用的设计模式。单例模式的主要作用是保证在Java程序中,某个类只有一个实例存在。一些管理器