《java与模式》读书笔记之五----多例模式


     多例模式是相对单例模式而言的。单例模式有且仅有一个实例,但是多例模式,顾问思义:允许存在有限个实例。 什么叫“有限个实例”? 就是说:有多少实例,我们是知道的,并不是不可以预知的, 如果一个类的构造函数是public 的,那么在任意地方都可以通过调用构造函数来创建实例,那么这样的实例是我们不能预知的。这是有上限多例模式,但是多例模式还有一种无上限多例模式。因此,多例模式有以下特点:

  • 允许有多个实例
  • 多例类自己负责创建、管理自己的实例、并向外界提供自己的实例。因此,他的构造函数也是private的,这点跟单例模式是相同的。


     首先,我们来看一个多例模式的例子。先来一个场景,相信大家都知道打麻将吧。每盘开局的时候,都会掷骰子,那么骰子只有2粒(大家没见过还有3粒的吧),把这句抽象一下,就是:骰子的个数是确定的,是有限个。 那么这个就符合我们多例模式的运用场景了。

package com.pattern.multilingual;

import java.util.Date;
import java.util.Random;

public class Die {

	/**
	 * 创建2个实例
	 */
	private static Die die1 = new Die();
	private static Die die2 = new Die();

	/**
	 * 私有构造子
	 */
	private Die() {
	}

	/**
	 * 工厂方法
	 * @param whichOne
	 * @return
	 */
	public static Die getInstance(int whichOne) {
		if (whichOne == 1) {
			return die1;
		}
		return die2;
	}
	
	/**
	 * 掷骰子
	 * @return
	 */
	public synchronized int dice(){
		Date d = new Date();
		Random r = new Random(d.getTime());
		int value = r.nextInt();
		value = Math.abs(value)%6+1;
		return value;
	}
}



测试类:

package com.pattern.multilingual;

public class Client {

	private static Die die1,die2;
	
	public static void main(String[] args) throws InterruptedException{
		die1 =  Die.getInstance(1);
		die2 = Die.getInstance(2);
		System.out.println(die1.dice());
		Thread.sleep(2000);
		System.out.println(die2.dice());
	}
}


无上限多例模式:事先并不知道实例的具体个数,因为实例个数无法预知,因为通常的做法是用集合来存储实例。下面来看一段国际化的例子:

package com.pattern.multilingual;

import java.util.HashMap;
import java.util.Locale;
import java.util.ResourceBundle;

public class LingualResource {

	private String localeCode = "en_US";
	private static final String FILE_NAME = "test";
	
	private static HashMap<String,LingualResource> instances = new HashMap<String,LingualResource>(19);
	private Locale locale = null;
	private ResourceBundle bundle = null;
	
	
	
	/**
	 * 构建LocaleCode
	 * @param language
	 * @param region
	 * @return
	 */
	private static String makeLocaleCode(String language,String region){
		return new StringBuilder(language).append("_").append(region.toUpperCase()).toString();
	}
	
	
	/**
	 * 构造子
	 * @param language
	 * @param region
	 */
	private LingualResource(String language,String region){
		localeCode =  makeLocaleCode(language,region);
		this.locale = new Locale(language,region);
		bundle =ResourceBundle.getBundle(FILE_NAME,locale);
		instances.put(localeCode, this);
	}
	
	private LingualResource(){}
	
	
	/**
	 * 工厂方法
	 * @param language
	 * @param region
	 * @return
	 */
	public synchronized static LingualResource getInstance(String language,String region){
		if(instances.get(makeLocaleCode(language,region)) != null){
			return instances.get(makeLocaleCode(language,region));
		}
		return new LingualResource(language,region);
	}
	
	
	/**
	 * 国际化方法
	 * @param code
	 * @return
	 */
	public String getLocaleString(String code){
		return this.bundle.getString(code);
	}
	
	
}


测试类:

package com.pattern.multilingual;

public class ResourceTest {


	public static void main(String[] args){
		LingualResource ling = LingualResource.getInstance("en", "US");
		String usName = ling.getLocaleString("name");
		
		LingualResource lingCN = LingualResource.getInstance("zh","CN");
		String cnName = lingCN.getLocaleString("name");
		
		System.out.println("usName:" + usName);
		System.out.println("cnName:" + cnName);
	}
	
	
}



资源文件:
 
test_en_US.properties
name=john
age=20

test_zh_CN.protites
name=\u7EA6\u7FF0
age=20


指印结果如下:
usName:john
cnName:约翰

其实在我们的开发中,其实很少这样写,通常像这种情况,可能在我们需要国际化的地方直接 new()的方式创建实例,相比之下采用这种方式,可以减少内存开支,省去了反复创建对象和回收对象的麻烦。

ps:在《JAVA与模式》一书中260页,这个国际化的例子,有错误,比如他的工厂方法是错误,而且存在大量的多余变量,部分问题考虑的很是不周到,有兴趣的朋友可以自己翻书对照一下,我的代码与书的代码。
同时,发现在本书中存在大量的错误,不知道是笔者手误,还是印刷出版社的印刷错误,希望大家在看此书时,抱着审视的态度。“尽信书则不如无书”,不过此书的例子仍然非常棒,这仍然是一本不错的书籍。



ps:多例模式,这个多例包括1个实例,因此多例模式是单例模式的推广,单例模式是多例模式的特例,另外给大家科普点小知识,为什么国际化(Internationalization)简称i18N? 那是因为I和n之间有18个字母,挺逗的命名。





你可能感兴趣的:(java,String,读书,Random,Class)