单例模式介绍
指一个类只有一个实例,且该类能自行创建这个实例的一种模式.。例如,Windows 中只能打开一个任务管理器,这样可以避免因打开多个任务管理器窗口而造成内存资源的浪费,或出现各个窗口显示内容的不一致等错误。
单例模式在现实生活中的应用也非常广泛,例如公司 CEO、部门经理等都属于单例模型。J2EE 标准中的 ServletContext 和 ServletContextConfig、Spring 框架应用中的 ApplicationContext、数据库中的连接池等也都是单例模式。
单例模式有 3 个特点 :
单例类只有一个实例对象;
该单例对象必须由单例类自行创建;
单例类对外提供一个访问该单例的全局访问点。
优点
1.单例模式可以保证内存只有一个示例,减少内存的开销
2.可以避免对资源的多重占用
3.单例模式设置全局访问点,可以优化和共享资源的访问
缺点
1.单例模式一般没有接口,扩展困难,如果要扩展则需要修改原来的代码,没有第二种途径,违背开闭原则。
2.,单例模式不利于代码调试。
3.单例模式的功能代码通常写在一个类中,如果功能设计不合理,则很容易违背单一职责原则。
单例模式的实现
单例方法有两种实现:懒汉式单例模式,饿汉式单例模式
结构
单例类:包含一个实例且能自行创建这个实例的类。
访问类:使用单例的类。
原型模式的应用场景
据上一章说到,张师傅,已经成为了远近闻名的蛋王,身价超过一个亿,自此他做的鸡蛋不卖了,直供观看,所以他是单例模式,只有一个实例
单例类:炒鸡蛋
访问类:main方法
懒汉式单例模式
public class SingletonPattern {
public static void main(String[] args) {
Fry_Egg.look();
Fry_Egg.look();
}
}
class Fry_Egg{
private static Fry_Egg fry_egg;
private Fry_Egg(){
System.out.println("我想看看你炒的鸡蛋");
}
public static Fry_Egg look(){
if (fry_egg==null){
fry_egg=new Fry_Egg();
System.out.println("炒完了,你看吧");
}else {
System.out.println("那放着呢,自己看");
}
return fry_egg;
}
}
输出结果
我想看看你炒的鸡蛋
炒完了,你看吧
那放着呢,自己看
饿汉式单例模式
public class SingletonPattern {
public static void main(String[] args) {
Fry_Egg.look();
Fry_Egg.look();
}
}
class Fry_Egg{
private static Fry_Egg fry_egg = new Fry_Egg();
private Fry_Egg(){
System.out.println("我想看看你炒的鸡蛋");
}
public static Fry_Egg look(){
System.out.println("那放着呢,自己看");
return fry_egg;
}
}
输出结果
我想看看你炒的鸡蛋
那放着呢,自己看
那放着呢,自己看
代码小结:
look其实就是getinstance() ,getinstance()就是获取实例,正常情况下方法名都是getinstance
懒汉式单例说明张师傅很懒,有人要看的情况下才会做,并且不会做第二份
饿汉式单例说明很着急,不管有没有人要看,他都会先做好
小结
1.单例的构造方法必须是私有化的(private防止new对象)
2.静态字段引用唯一实例
3.通过静态方法返回实例
4.懒汉式返回对象需要synchronized加锁
5.饿汉式的话是声明并创建对象
懒汉式的话只是声明对象,在调用该类的 getinstance() 方法时才会进行 new 对象。
6.饿汉式单例在类创建的同时就已经创建好一个静态的对象供系统使用,以后不再改变,所以是线程安全的
懒汉式如果是在多线程程序中,声明时要加volatile,返回对象时要加synchronized锁