单例模式---设计模式(一)

来源:互联网 发布:情景喜剧排行知乎 编辑:程序博客网 时间:2024/06/05 20:50

单例模式:确保一个类最多只有一个实例,并提供一个全局访问点

单例模式类图:
这里写图片描述

类图说明:

首先说明一下该类图中的符号:
类:
使用三层矩形框表示
第一层:显示类的名称,如果是抽象类,则就用斜体显示
第二层:字段和属性
第三层:类的方法

“+”:表示public
“-”:表示private
“#”:表示protected

接口:
使用两层矩形框表示,与类图的区别主要是顶端有<<interface>>显示
第一层:接口的名称
第二层:接口的方法

继承类(extends):
用空心三角形+直线表示

实现接口(implements):
用空心三角形+虚线表示

关联(Association):
用实线箭头来表示

聚合(Aggregation):
用空心菱形+实线箭头来表示
聚合:表示一种弱的‘拥有’关系,体现的是A对象可以包含B,但B对象不是A对象的一部分,例如:公司和员工

组合(Composition):
用实心菱形+实线箭头来表示
组合:部分和整体的关系,并且生命周期是相同的。例如:人和手

依赖(Dependency):
用虚线箭头来表示
例如:动物和氧气

单例模式

Singleton类称为单例类,通过使用private的构造函数,确保了在一个应用中只产生一个实例,并且是自行实例化的(在Singleton中自己使用new Singleton())。
单例模式的通用代码:
饿汉式:

package singletontest;/** * 单例模式(饿汉模式) * 应用场合:有些对象只需要一个就足够了,如古代皇帝,老婆 * 作用:保证整个应用程序中某个实例有且只有一个 * 类型:懒汉模式,饿汉模式 * @author 张耀晖 * */public class Singleton {    //1.将构造方法私有化,不允许外部直接创建对象    private Singleton(){    }    //2.创建类的唯一实例,使用private static修饰    private static Singleton singleton = new Singleton();    //3.提供一个用于获取实例的方法,使用public static修饰    public static Singleton getInstance(){        return singleton;    }}

懒汉式:

package singletontest;/** * 懒汉模式 * 区别:饿汉模式的特点是加载类时比较慢,但运行时获取对象的速度比较快,线程安全 *     懒汉模式特点是加载类时比较快,但运行时获取对象速度比较慢,线程不安全 * @author 张耀晖 * */public class Singleton2 {    //1.将构造方法私有化,不允许外边直接创建对象    private Singleton2(){    }    //2.声明类的唯一实例,使用private static修饰    private static Singleton2 singleton2;    //3.提供一个用于获取实例的方法,使用public static修饰    public static Singleton2 getInstance(){        if(singleton2==null){            singleton2 = new Singleton2();        }        return singleton2;    }}
package singletontest;public class Test {    public static void main(String[] args) {        //饿汉模式        Singleton s1 = Singleton.getInstance();        Singleton s2 = Singleton.getInstance();        if(s1==s2){            System.out.println("s1和s2是同一个实例");        }else{            System.out.println("s1和s2不是同一个实例");        }        //懒汉模式        Singleton2 s3 = Singleton2.getInstance();        Singleton2 s4 = Singleton2.getInstance();        if(s3==s4){            System.out.println("s3和s4是同一个实例");        }else{            System.out.println("s3和s4不是同一个实例");        }    }}

运行结果:
这里写图片描述

注意:
懒汉式是存在线程不安全问题的。
懒汉式在低并发的情况下有可能不会出现问题,但是当高并发的情况下则可能在内存中出现多个实例。
eg:如果一个线程A执行到singleton2 = new Singleton2(),但还没有获得对象(对象初始化是需要时间的),第二个线程B也在执行,执行到singleton2==null的判断,那么线程B获得判断条件也是为真,于是继续运行下去,线程A获得一个对象,线程B也获得一个对象,在内存中就出现了两个对象。

解决懒汉式的线程不安全问题的方法:
在getInstance()方法前加synchronized关键字。不过这样的话只适应调用实例对象少的情况,如果调用实例对象比较频繁synchronized就会影响系统的执行效率。那么就建议使用饿汉式。
饿汉式也有一定的问题,在不使用类的实例对象的时候也会创建该类的实例对象,造成一定的资源浪费。

  1. 单例模式的优点
    •由于单例模式在内存中只有一个实例,减少了内存开支,特别是一个对象需要频繁的被创建、销毁,而且创建或销毁时性能又无法优化,单例模式的优势就非常明显;
    •由于单例模式只生成一个实例,减少了系统性能开销,当一个对象的产生需要比较多的资源时,如读取配置、产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后永久驻留内存的方式来解决(在Java EE中采用单例模式时需要注意JVM垃圾回收机制);
    •单例模式可以避免对资源的多重占用,例如一个写文件动作,由于只有一个实例存在内存中,避免对同一个资源文件的同时写操作。
    •单例模式可以在系统设置全局的访问点,优化环共享资源访问,例如可以设计一个单例类,负责所有数据表的映射处理。

  2. 单例模式的缺点
    •单例模式没有接口,扩展很困难,若要扩展,除了修改代码没有第二种途径可以实现。单例模式为什么不能增加接口呢?因为接口对单例模式是没有任何的意义,它要求“自行实例化”,并且提供单一实例、接口或抽象类是不可能被实例化的。
    •单例模式对测试是不利的。在并行开发环境中,如果单例模式没有完成,是不能进行测试的,没有接口也不能使用mock的方式虚拟一个对象。
    •单例模式与单一职责原则有冲突。一个类应该只实现一个的逻辑,而不关心它是否是单例的,决定它是不是要单例是环境决定的,单例模式把“要单例”和业务逻辑融合也在一个类中。

  3. 单例模式的使用场景

    在一个系统中,要求一个类有且仅有一个对象,如果出现多个对象就会出现“不良反应”时,则可以采用单例模式,具体的场景如下:
    •要求生成唯一序列号的环境;
    •在整个项目中需要有访问一个共享访问点或共享数据,例如一个Web页面上的计数器,可以不用每次刷新都记录到数据库中,使用单例模式保持计数器的值,并确保是线程安全的;
    •创建一个对象需要消耗的资源过多,如要访问IO、访问数据库等资源;
    •需要定义大量的静态常量和静态方法(如工具类)的环境,可以采用单例模式(当然,也可以直接声明为static的方式);

单例模式的扩展

现在有一个问题:如果要求一个类只能产生固定数量(大于1个)的对象怎么办?

package com.test.singletonTest;import java.util.ArrayList;import java.util.Random;/** * 单例模式的扩展,产生固定数量的(大于1个)的实例对象 * 2015年9月17日 下午5:08:15 * @author 张耀晖 * */public class SingletonTest {    private static int maxnum = 3;//定义最多能产生的实例对象的数量    private static ArrayList<SingletonTest> singletonList = new ArrayList<SingletonTest>();//定义一个集合,容纳所有的实例对象    private static ArrayList<String> singletonNameList = new ArrayList<String>();//定义一个集合,容纳所有对象的私有属性    //当前实例对象的标号    private static int countOfNum;    //产生所有的对象    static{        for (int i = 0; i < maxnum; i++) {            singletonList.add(new SingletonTest("实例对象:"+i+1));        }    }//  //将类中默认的无参构造方法重写为private,防止在外部创建该类的实例对象//  private SingletonTest(){//      //  }    //传入实例对象的名称,创建实例对象    private SingletonTest(String name){        singletonNameList.add(name);    }    //随机获得一个实例对象    public static SingletonTest getInstance(){        Random random = new Random();        countOfNum = random.nextInt(maxnum);        //随机取出一个实例对象        SingletonTest singletonTest = singletonList.get(countOfNum);        return singletonTest;    }    //获取实例对象的私有属性    public static String getSingletonName(){        String name = singletonNameList.get(countOfNum);        return name;    }}
1 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 初一数学考了3分怎么办 初二物理太差该怎么办 三年级孩子字写的差怎么办 小学三年级数学才考86怎么办 小孩子一发脾气就打妈妈怎么办 孩子做错事不肯道歉怎么办 小孩写作业注意力不集中怎么办 六年级的数学下册差怎么办 一年级小孩做作业慢怎么办 静不下心写作业怎么办 二年级应用题太差怎么办 小学二年级数学差怎么办 小学二年级成绩差怎么办 6个月小孩爱动怎么办 儿子叛逆期我该怎么办 宝宝两岁好动不听话怎么办 生宝宝后奶水少怎么办 生了孩子没出来怎么办 孩子在学校表现不好怎么办 3岁半宝宝话太多怎么办 孩子不喜欢和小朋友玩怎么办 孩子不喜欢和小朋友说话怎么办 4岁半宝宝不听话怎么办 小孩在学校打老师怎么办 老师老找孩子时怎么办 幼儿园老师批评孩子后家长怎么办 老师跟家长吵架了怎么办 孩子在幼儿园被老师孤立怎么办 学生在幼儿园被老师欺负怎么办 小孩脚痒怎么办小窍门 小孩肚子病怎么办天天说 幼儿园幼儿信息表填错了怎么办 水浒传书孩子说看不懂怎么办 孩子丢了书老师怎么办 小朋友做错事不承认老师怎么办 教师被学生骂后怎么办 嘴吧里面长泡怎么办 有个小孩怕下雨怎么办? 幼儿的家长打我怎么办 老师打学生被家长起诉怎么办 家长在学校打了老师怎么办