Java设计模式之单例(Singleton)与享元(Flyweight)

很久之前就阅读过GoF的设计模式,由于才疏学浅,又没有什么实践经验,完全是一个学生的走马观花。现在由于在实际工作中的需要,还是要一遍遍反复回味这些优秀的设计模式,正所谓温故而知新。
首先来说一说单例(Singleton)模式,我想这是非常容易理解的一种设计模式。所谓单例,就是要求在应用运行过程中,只存在某个类的一个实例,所有其它对象都只可能引用到这一个实例。为何要有单例模式,有一种说法是:节省内存。这个观点,不能说它是错误的,因为单例确实可以做到这一点,但这并不是单例模式出现的本因。我认为,单例模式是为了处理某些逻辑问题的。比如说,某个类,如果同时存在多个实例,就可能引发逻辑错误。比如一个计数类,负责对每一次web请求计数,假如多个实例同时出现,逻辑上就会发生错误。因为每一个实例都不能真实的反映访问量。

实现单例模式,也很简单,我们常见到的方式如下:

public class Singleton{
private static Singleton instance = null;
//一些其它数据域

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

这段代码的特殊之处:
1. 自己持有一个对自己引用的[b]静态[/b]数据域
2. 私有构造函数
3. 通过[b]静态[/b]getInstance()获得实例

正是由于以上的3点,才能保证单例不会被以new的方式得到,只能通过静态方法获得。
上面的这段代码,存在这一个隐患:
它并不是线程安全的,当面对一个并发访问的应用环境中时,有可能会出现2个实例。
比如,线程A执行到insta = new...时,此时,instance还没有得到真实的引用,此时线程B再次判断,发现instance仍是null,将会有一次创建新的实例。
下面我们将展示上述隐患:


public class Singleton {
private static Singleton instance = null;
private static int count=0;//记录被创建实例的总数
private int id;//当前实例的id

private Singleton(){
count++;
id = count;
}
public static Singleton getInstance(){
if(instance==null){
instance = new Singleton();
}
return instance;
}
public int getId() {
return id;
}
}


简单的测试线程


public class TestThread implements Runnable {


public void run() {
// TODO Auto-generated method stub
Singleton myInstance = Singleton.getInstance();
System.out.println(myInstance.getId()+"th instance is created.");

}

}

Main函数:

public class Main {

/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
TestThread threadA = new TestThread();
TestThread threadB = new TestThread();
new Thread(threadA).start();
new Thread(threadB).start();

}

}

结果:
在上述条件下,结果具有不确定性,与线程的调度有一定关系,所以,有时会创建一个实例,有时会创建两个实例:
1th instance is created.
1th instance is created.
-----------
2th instance is created.
1th instance is created.
-----------
1th instance is created.
2th instance is created.
下面,我们将getInstance方法声明成为synchronized的,运行结果始终是:
1th instance is created.
1th instance is created.
==================================================
享元模式 对于享元模式的认识,也是刚刚开始。享元来自于拳击术语,即轻量级(flyweight),意指面向对象程序设计中很多粒度很小的类。这些类具备这样的特点:它的某些属性或行为,与其它的类呈现包容关系。而且这些类的状态的变化,也是直接反映到所有包容它的类类中。就是说,这些类是可以被share的,所以称之为享元(共享的单元??)。
一个典型的例子,我觉得就是编辑器与文字的关系,26个英文字母,即可作为享元来使用。
那么,它会被哪些类共享呢?我们可以考虑由一个font类,那么,一个编辑器有很多种字体,字体有颜色 大小之类的属性,也有字母的值(a,b,c...),那么把这些字母的值和其固有的一些方法抽象出来作为享元。
也许你可能会觉得,不就是一个char的字符值么,有必要抽象成一个类么。但是,如果你有一个几百万个字母的文章需要处理,那么100w*sizeof(char)>>26*sizeof(char)+othercost的。

至于其它的应用场景,需要在现实应用中自己来思考抽象了。具体的实现也不再多谈,可以上网搜索。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值