介绍
单例的对象必须保证只有一个实例存在,不能自由构造对象
定义
某一个类只能有一个实例,并自行实例化且向整个系统提供这个实例
使用场景
- 产生多个对象导致资源浪费
- 创建一个对象消耗资源过多如访问IO、数据库
- 某种类型的对象只能有一个,如一个仓库
UML类图
实现单例的关键
- 构造函数私有化不对外开放
- 通过静态方法或者枚举返回单例对象
- 确保单例对象只有一个,尤其是在多线程环境下
- 确保单例对象在反序列化时不会重新构建对象
问题案例
这个案例展示的是为什么要使用单例模式,或者说,我们不使用单例会有什么危害
仓库
/**
* 仓库类
*/
public class StoreHouse {
//仓库商品数量
private int quantity=100;
//货物进出
public void setQuantity(int quantity) {
this.quantity = quantity;
}
//货物数量
public int getQuantity() {
return quantity;
}
}
搬货工人
/**
* 搬货工人类
*/
public class Carrier {
//public可以让测试的时候选择到对象
public StoreHouse mStoreHouse;
public Carrier(StoreHouse storeHouse){
this.mStoreHouse = storeHouse;
}
//搬货进仓库
public void MoveIn(int i){
mStoreHouse.setQuantity(mStoreHouse.getQuantity()+i);
}
//搬货出仓库
public void MoveOut(int i){
mStoreHouse.setQuantity(mStoreHouse.getQuantity()-i);
}
}
测试一下
public class test {
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("两个是不是同一个?");
//这里用equals而不是用 == 符号,因为 == 符号只是比较两个对象的地址
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
仓库商品余量:50
如何更改(使用静态内部类方式实现单例)
按照实现步骤完成
仓库类
/**
* 仓库类
*/
public class StoreHouse {
//仓库商品数量
private int quantity=100;
private StoreHouse() {
}
private static class StoreHouseHolder{
private static final StoreHouse storeHouse=new StoreHouse();
}
public static StoreHouse newInstance(){
return StoreHouseHolder.storeHouse;
}
//货物进出
public void setQuantity(int quantity) {
this.quantity = quantity;
}
//货物数量
public int getQuantity() {
return quantity;
}
}
搬运工人不需要改
测试一下
public class test {
public static void main(String[] args) {
StoreHouse mStoreHouse1 = StoreHouse.newInstance();
StoreHouse mStoreHouse2 = StoreHouse.newInstance();
Carrier Carrier1 = new Carrier(mStoreHouse1);
Carrier Carrier2 = new Carrier(mStoreHouse2);
System.out.println("两个是不是同一个?");
//这里用equals而不是用 == 符号,因为 == 符号只是比较两个对象的地址
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());
}
}
测试结果
两个是不是同一个?
是同一个
仓库商品余量:70
仓库商品余量:20