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. 自己持有一个对自己引用的 静态数据域
2. 私有构造函数
3. 通过 静态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的。

至于其它的应用场景,需要在现实应用中自己来思考抽象了。具体的实现也不再多谈,可以上网搜索。

你可能感兴趣的:(java,设计模式,thread,Web,单元测试)