Java设计模式之一 单例设计模式

1、什么叫设计模式:

设计模式的概念首先来源于其它行业:建筑业,在早起建房子的时候,肯定是经验缺乏、显得杂乱无序的,这就会造成很多问题,在行业发展过程,通过不断的经验积累,前辈们针对这些问题提出了合理解决方案,这就是设计模式,参照设计模式往往可以解决很多问题,在计算机编程方面,也会出现类似问题,所以牛人们把这些解决问题的方案进行归类和总结,形成了面向对象编程的23种设计模式。

2、单例模式(特点):

Java中单例模式定义:“一个类有且仅有一个实例,并且自行实例化向整个系统提供。”通过使用设计模式可以让我们的代码复用性更高,可维护性更高,让你的代码写的更优雅。

3、动机(单例模式的由来):

1、首先对象可以看着类的实体化副本,就像图纸和图纸所打造的实体,同一个类的不同对象,是属性的差异,但是有时候我们并不需要内存中存在该类多个对象,比如一个系统只能有一个窗口管理器或文件系统,如在Windows中就只能打开一个任务管理器。如果不使用机制对窗口对象进行唯一化,将弹出多个窗口,如果这些窗口显示的内容完全一致,则是重复对象,浪费内存资源;如果这些窗口显示的内容不一致,则意味着在某一瞬间系统有多个状态,与实际不符,也会给用户带来误解,不知道哪一个才是真实的状态。因此有时确保系统中某个对象的唯一性即一个类只能有一个实例非常重要;再比如软件的配置文件有多个用户去获取配置信息的时候,如果也是创建多个对象,他们是分别操作不同的对象,数据是不能实时共享的,而如果内存是一个对象,则可以解决这个问题。

2、如果一个类的对象有可能在内存出现大量重复的时候,某种程度限制对象的创建,可以减少内存的消耗,当然这是一个比较牵强的动机。

4、思路(解决问题的历程):

解决如上问题,其实首要想到的方法就是通过给类中成员添加静态(static)修饰的方式,这样就形成了数据的共享,但是这里存在的主要的问题就是静态成员在内存的驻留时间过长,至少比对象长,所有通过唯一对象的方式更加适合。

  • 如何保持对象的唯一性:

1、不允许其它类中创建(new)该类的对象,因为这是无法控制创建数量的。

2、必须在该类中提供一个该类的唯一实例。

3、对外提供一个方法,以便其它类可以获取该实例。

具体办法:

第一点:不允许其它类中创建(new)该类的对象,因对象的创建必须调用构造函数,所以把默认构造函数私有化。

第二点:可以在类中创建(new)本类的对象。

第三点:构建的一个方法,返回该类的对象。

代码历程:

public class Singleton {
	private Singleton(){};//满足第一点

	public Singleton getInstance(){//似乎满足第二点
		return new Singleton;//似乎满足第三点
	}
}

问题:为什么第二点和第三点加上似乎呢?仔细思考一下就会发现问题:

  1. 第二点中,因为该类不能创建对象,所以getInstance()无法调用;
  2. 第三点中,假如getInstance()可以调用,但每一次调用都会创建一个新的对象,不符合要求。

解决办法:

  1. 给方法加上静态修饰(static),通过类名调用。
  2. 创建一个对象的引用变量,指向该类的对象,在getInstance()中返回对象的引用。

修改后:

public class Singleton {
	Singleton instance = new Singleton();
	private Singleton(){};
	public static Singleton getInstance(){
		return instance;
	}
}

问题:

  1. 在静态方法getInstance中是无法调用非静态成员变量的,所以需要把instance变成静态成员。
  2. 如第一条成立,可以通过Singleton.instance获取到对象的实例,这样等效于调用getInstance方法,所以最好加上私有修饰符,禁止该途径调用对象实例。

一、正确代码(饿汉式):

public class Singleton {
	private static Singleton instance = new Singleton();
	private Singleton(){};
	public static Singleton getInstance(){
		return instance;
	}
}

这个时候我们以为掌握了单例模式,其实是掌握了,但仅仅是单例设计模式的一种写法,如上写法称为”饿汉式“,因instance是静态成员变量,所以在jvm对该类加载过程中,就进行对象的实例化,所以是提前创建实例。

另外一种写法,就是在getInstance调用时才进行对象的创建,这种写法又称为”延迟加载“或者”懒汉式“。

二、懒汉式(延迟加载)。

public class Singleton {
	private static Singleton instance = null;
	private Singleton(){};
	public static Singleton getInstance(){
		if(instance == null){
			instance = new Singleton();
		}
		return instance;
	}
}

问题:懒汉式的写法,在多线程中会出现问题,即创建多个对象,如下图所示:

public class Singleton {
	private static Singleton instance = null;
	private Singleton(){};
	public static Singleton getInstance(){
		if(instance == null){
			--> 一个A线程进入并挂起。
			--> 此时一个B线程进入,这种情况会造成两个线程都会执行new Singleton操作,这样就会在内存存在多个该类对象。
			instance = new Singleton();
		}
		return instance;
	}
}

解决方案:加锁。

三、懒汉式同步锁(懒汉式线程不安全的解决方案)。

public class Singleton {
	private static Singleton instance = null;
	private Singleton(){};
	public static synchronized Singleton getInstance(){
		if(instance == null){
			instance = new Singleton();
		}
		return instance;
	}
}

另一种写法:

public class Singleton {
	private static Singleton instance = null;
	private Singleton(){};
	public static  Singleton getInstance(){
		synchronized(Singleton.class){ //同步代码块,锁不能为this,因为该方法是静态方法,不能获取到this对象。
			if(instance == null){
				instance = new Singleton();
			}
			return instance;
		}

	}
}

问题:每次调用getInstance时都会判断锁,这样会降低程序的效率。注:锁(Singleton.class)该类所属的字节码文件对象。

四、懒汉式双重校验锁。

public class Singleton {
	private static Singleton instance = null;
	private Singleton(){};
	public static  Singleton getInstance(){
		if(instance == null){
			synchronized(Singleton.class){
				if(instance == null){
					instance = new Singleton();
				}
				return instance;
			}
		}

	}
}

优点:只有第一次调用getInstance时,即instance等于null时才会判断锁,这样就提搞了效率。

5、单例模式的使用:

如果仅仅如上面所示的方式 ,去创建这些代码是没有意义,正确使用单例模式的方式就是在原有代码上,加上这些代码。

添加单例模式前:

public class Test {
	public static void main(String[] args){
		Person p1 = new Person();
		p1.setName("Jack");
		p1.setAge(18) ;
		Person p2 = new Person();
		p2.setName("David");
		p2.setAge(20);

		System.out.println(p1.getName() + ":" + p1.getAge());
		System.out.println(p2.getName() + ":" + p2.getAge());
	}
}

class Person{
	private String name ;
	private int age;

	public void setName(String name){
		this.name = name;
	}
	public String getName(){
		return name;
	}

	public void setAge(int age){
		this.age = age;
	}
	public int getAge(){
		return age;
	}

}

运行结果:

Jack:18

David:20

单例模式后:

public class Test {
	public static void main(String[] args){
		Person p1 = Person.getInstance();
		p1.setName("Jack");
		p1.setAge(18) ;
		Person p2 = Person.getInstance();
		p2.setName("David");
		p2.setAge(20);

		System.out.println(p1.getName() + ":" + p1.getAge());
		System.out.println(p2.getName() + ":" + p2.getAge());
	}
}

class Person{
	private String name ;
	private int age;

	private static Person instance = new Person();//2.本类中创建该类的对象
	private Person(){};//1.私有构造函数
	public static Person getInstance(){//3.创建一个方法,向外部提供该类的对象
		return instance;
	}

	public void setName(String name){
		this.name = name;
	}
	public String getName(){
		return name;
	}

	public void setAge(int age){
		this.age = age;
	}
	public int getAge(){
		return age;
	}

}

运行结果:

David:20

David:20

目的保证了对象的唯一性

6、参考:

1、毕向动老师的视频:JavaSE基础视频08 -【04-面向对象(单例设计模式-概述&体现).avi】、【05-面向对象(单例设计模式-内存图解).avi】、【06-面向对象(单例设计模式-懒汉式).avi】、传智播客毕向东Java基础视频教程-day11-14-多线程(多线程-单例设计模式-懒汉式)

2、百度百科:单例模式

3、stormzhang博客:设计模式之单例模式Android设计模式之单例模式单例模式的一些注意点

时间: 2024-10-19 11:41:11

Java设计模式之一 单例设计模式的相关文章

java设计模式之单例设计模式

设计模式:解决某一类问题最行之有效的方法. java中23种设计模式. 单例设计模式:解决一类在内存中只存在一个对象. Runtime()方法就是单例设计模式进行设计的. 解决的问题:保证一个类在内存中的对象唯一性. 比如:多程序读取一个配置文件时,建议配置文件封装成对象.会方便操作其中数据,又要保证多个程序读到的是同一个配置文件对象,就需要该配置文件对象在内存中是唯一的. 1.为了避免其他程序过多建立该类对象,先禁止其他程序建立该类对象. 2.还为了让其他程序可以访问该类对象,只好在本类中自定

笔记:Java中的单例设计模式

之前接触过单例模式,当初不明白这样的设计用意,今天特地研究了下java中的单例设计模式的用处及用法. 单例模式:单例模式是一种常用的软件设计模式.在它的核心结构中只包含一个被称为单例类的特殊类.一个类有且仅有一个实例,并且自行实例化向整个系统提供. 单例模式的用处:一个系统中可以存在多个打印任务,但是只能有一个正在工作的任务:一个系统只能有一个窗口管理器或文件系统:一个系统只能有一个计时工具或ID(序号)生成器.如在Windows中就只能打开一个任务管理器.如果不使用机制对窗口对象进行唯一化,将

java软件设计模式只单例设计模式

概述 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了可重用代码.让代码更容易被他人理解.保证代码可靠性. 毫无疑问,设计模式于己于他人于系统都是多赢的:设计模式使代码编制真正工程化:设计模式是软件工程的基石脉络,如同大厦的结构一样. 设计模式分为三种类型,共23种.创建型模式:单例模式.抽象工厂模式.建造者模式.工厂模式.原型模式.结构型模式:适配器模式.桥接模式.装饰模式.组合模式.外观模式.享元模式.代理模式.

设计模式总纲——单例设计模式

前两天写了设计模式总纲,今天就来讲讲我们在工程代码中最最最常用的设计模式了——单例设计模式,这个模式在工程代码上的出现率几乎为99.99999%,但是虽然很常用,但是用的好的人却不多,今天我们就来深入的说一说单例设计模式. 在学习一项新的知识之前,我们都要向自己提出三个问题,为什么要用这个知识,这个知识用在哪里,这个知识怎么用?既 why,where,how,3W模式,我们先来谈谈为什么需要单例设计模式,先来想想,如果一个工具类,比如一个读取配置文件的工具类,这类工具只是特定的功能类,既读取指定

设计模式之-----------单例设计模式

饿汉式: class Single { //   提前做好! private static final Single s = new Single(); //  私有化 构造函数  无法使用new 创建对象! private Single(){} //  对外提供接口 public static Single getInstance() { return s; } } 懒汉式: 懒汉 顾名思义  就是懒呗 什么时候用到 什么时候创建! class Single1 { private static

java设计模式_single(单例设计模式)

设计模式:解决某一类问题最行之有效的方法,java中有23种设计模式 一.单例设计模式概述: 1.解决一个类在内存中只有一个对象(保证一个类仅有一个实例,并提供一个访问他的全局访问点)  2.要保证对象的唯一: 1.为了避免其他程序过多的建立该类对象,先禁制其他程序建立该类对象 2.为了让其他程序可以访问到该类对象,只好在本类中,自定义一个对象 3.为了 方便其他程序对自定义对象的访问,可以对外提供一些访问方式 3.代码实现步骤: 1.将构造函数私有化 2.在类中创建一个本类对象 3.给外部提供

【设计模式】单例设计模式的N中Java实现方法

特点 单例模式的特点: 1.只能有一个实例: 2.必须自己创建自己的一个实例: 3.必须给所有其他对象提供这一实例. 饿汉式单例模式 也称为预先加载法,实现方式如下: [java] view plaincopy class Single { private Single()( Syustem.out.println("ok"); ) private static Single instance = new Single(); public static Single getInstan

Java设计模式之单例设计模式(Singleton)

单例设计模式 单例模式在日常开发中用的也比较多,顾名思义就是一个类的对象在整个系统中只能有一个 优点: 1.单例模式会阻止其他对象实例化其自己的单例对象副本,从而确保所有对象都访问唯一实例 2.由于在整个系统中指存在一个实例对象,避免了频繁的创建和销毁对象,因此可以节约系统资源 3.避免了对共享资源的多重占用 4.自行创建这个单例对象,避免使用时再去创建 缺点: 1.单例模式没有抽象层,所以扩展性比较差 2.不适用于变化的对象,如果同一类型的对象需要在不同的场景下使用,单例就会引起数据的错误 3

Java面向对象_单例设计模式

单例设计模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点 1.构造方法私有化 2.声明一个本类对象 3.给外部提供一个静态方法获取对象实例 两种实现方式:饿汉式和懒汉式 何种情况下使用呢?当一个类中没有属性(对象的状态):该类作为工具类使用非常频繁: 好处:节省内存(因为不断创建对象会消耗内存) 1 public class Practice14 { 2 3 public static void main(String[] args) { 4 // TODO Auto-generate