Android设计模式之单例模式

发表于:2016-8-02 11:09

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:涤生727    来源:51Testing软件测试网采编

  概述
  单例模式是应用最广的模式之一,在应用这个模式时,单例对象的类必须保证只有一个实例存在。许多时候整个系统只需要拥有一个全局对象,这样有利于我们协调系统整体的行为。如在一个应用中,应该只有一个ImageLoader实例,这个ImageLoader中又含有线程池、缓存系统、网络请求等,很消耗资源。因此不应该让它构造多个实例。这样不能自由构造对象的情况,就是单例模式的使用场景。
  定义
  确保一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。
  使用场景
  确保某个类有且只要一个对象的场景,避免产生多个对象消耗过多的资源,或者某种类型的对象只应该有且只有一个。例如,创建一个对象需要消耗的资源过多,如要访问IO和数据库等资源,这时就要考虑使用单例模式。
  UML类图
  单例模式的UML类图如下:
  角色介绍:
  · Client:高层客户端
  · Singleton:单例类
  实现单例模式主要有以下几个关键点:
  · 构造函数不对外开放,一般为private;
  · 通过一个静态方法或者枚举返回单例类对象;
  · 确保单例类的对象有且只有一个,尤其是在多线程环境下;
  · 确保单例类对象在反序列化时不会重新构建对象;
  单例模式中实现比较困难的是在多线程环境下构造单例类的对象有且只有一个。
  简单示例
  单例模式在设计模式中是结构比较简单的,只有一个单例类,没有其他层次结构和抽象。该模式需要确保该类只能生成一个对象,通常是该类需要消耗较多的资源或者没有对个实例的情况。例如一个公司只有一个CEO、一个应用只有一个Application对象等。
  下面以公司里的CEO为例来简单演示一下,一个公司可以有多个VP、无数个员工,但只有一个CEO,代码如下:
/**
*
* 普通员工
*
*/
public class Staff {
public void work() {
//干活
}
}
//副总裁
public class VP extends Staff {
@Override
public void work() {
// 管理下面的经理
}
}
//CEO,饿汉式单例
public class CEO extends Staff {
private static final CEO mCEO = new CEO();
private CEO() {
}
//公有的静态函数,对外暴露获取单例对象的接口
public static CEO getCeo() {
return mCEO;
}
@Override
public void work() {
// 管理VP
}
}
//公司类
public class Company {
private List<Staff> mStaffs = new ArrayList<Staff>();
public void addStaff(Staff staff) {
mStaffs.add(staff);
}
public void showStaffs() {
for(Staff staff : mStaffs) {
System.out.println("Obj: " + staff.toString());
}
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Company company = new Company();
//CEO对象只能通过getCeo获取
Staff ceo1 = CEO.getCeo();
Staff ceo2 = CEO.getCeo();
company.addStaff(ceo1);
company.addStaff(ceo2);
Staff vp1 = new VP();
Staff vp2 = new VP();
company.addStaff(vp1);
company.addStaff(vp2);
Staff staff1 = new Staff();
Staff staff2 = new Staff();
company.addStaff(staff1);
company.addStaff(staff2);
company.showStaffs();
}
  运行输出结果如下:
  Obj: com.liuguoquan.design.single.CEO@15db9742
  Obj: com.liuguoquan.design.single.CEO@15db9742
  Obj: com.liuguoquan.design.single.VP@6d06d69c
  Obj: com.liuguoquan.design.single.VP@7852e922
  Obj: com.liuguoquan.design.single.Staff@4e25154f
  Obj: com.liuguoquan.design.single.Staff@70dea4e
  从上面代码可以看出,CEO类不能通过new的形式构造函数,只能通过CEO.getCeo()方法来获取,而这个CEO对象是静态对象,并且在声明的时候就已经初始化,这就保证类CEO对象的唯一性。
  从输出结果中可以看出,CEO两次输出的CEO对象的地址都一样,说明是同一个CEO对象;而VP、Staff等类型的对象都是不同的。
  实现方式
  饿汉式
  饿汉式模式是在声明静态对象时就已经初始化,这种方式简单粗暴,如果单例对象初始化非常快,而且占用内存小的时候这种方式是比较适合的,可以直接在应用启动时加载初始化。实现如下:
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton() {
}
public static Singleton getInstance() {
return instance;
}
}
  懒汉式
  懒汉模式是声明一个静态对象,并且在用户第一次调用getInstance时进行初始化。
public class Singleton {
private static Singleton instance = null;
private Singleton() {
}
public static Singleton getInstance() {
synchronized(Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
  getInstance方法中添加了Synchronized关键字,也就是同步类synchronized关键字包含的代码块,这就是上面所说的在多线程中保证单例对象唯一性的手段。但是仍存在一个问题,即使instance已经初始化,每次调用getInstance方法都会进行同步,这样会消耗不必要的资源,这也是懒汉式存在的最大问题。
  懒汉单例模式的优点是只有在使用时才会被实例化,在一定程度上节约了资源,缺点是第一次加载时需要及时进行实例化,反应稍慢,最大问题是每次调用geInstance都进行同步,造成不必要的同步开销,这样模式一般不建议使用。
21/212>
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号