第一招:单态模式(Singleton)
如果希望在系统运行的过程中,一个类始终只存在一个实例时,就可以用单态模式。比如对一个程序而言,当前的显示屏、CPU、剪切板始终只有一个,应该用单态模式 来描述这些类。
在一个类中应用单态模式有以下两种常见的方式,称之为“懒汉式”和“饿汉式”。
懒汉式的Singleton饿汉式的Singleton
public class Test {
private Test() { }
private static Test instance = new Test();
public static Test getInstance() {
return instance;
}
}public class Test {
private Test() { }
private static Test instance = null;
public synchronized static Test getInstance() {
if (instance == null) {
instance = new Test();
}
return instance;
}
}
按照下面三个步骤就可以实现一个标准的Singleton:
①.将构造函数声明成私有(从语法上防止其他类实例化)
②.声明一个私有静态的自身对象
③.声明一个共有静态的方法,返回自身对象
上面的两端代码在2,3步略有不同,饿汉式可以确保当用户调用getInstance方法后才实例化自身对象,如果实例化的代价很昂贵的话,那么饿汉式可以避免无必要的实例化。但是在多用户的系统中可能会重复实例化,所以方法声明成了synchoronized,会影响一些效率。
单态模式在Java类库中的应用是java.lang.Runtime这个类。还有两个类很像,但不是单态模式:java.lang.Math和java.awt.Toolkit,原因是前者没有返回唯一的自身对象,后者返回的是子类对象。
第二招:简单工厂(Simple Factory)
简单工厂一般用来返回不同的子类对象。
举个例子,我想开一家店,卖各种电脑配件,包括CPU,显示器,内存,硬盘等,产品结构图如下:
图:产品结构
很容易看出,CPU是一个抽象类,有Intel的CPU和AMD的CPU两个子类,显示器则分为了电子管显示器和液晶显示器。好了,现在如果有顾客要来买CPU,该怎么处理呢?你不能直接给顾客一个CPU,因为CPU是抽象类,没有对象,必须要问“您需要什么样的CPU ?”,如果顾客答“我要Intel的”,就可以实例化一个IntelCPU对象给顾客了。
这个过程看上去理所当然,但是隐藏了一个问题,顾客必须清楚地知道存在IntelCPU这个子类,并了解它的特点,然而并非每个顾客都对自己要买的产品了如指掌。记得若干年前,我和大学同学准备去肯德基开开洋荤,第一次来这种“高档”的餐厅难免令人有些紧张,好不容易排到柜台前,我谨慎的对服务员说:“要两个汉堡”,服务员立刻问道:“请问要哪种汉堡?”,我立刻精神崩溃,啥,汉堡还分好几种?!我只得小声问道:“都有哪几种?”,服务员飞快的报出“香辣鸡腿堡、劲脆鸡腿堡、田园脆鸡堡……”,可怜的我因为紧张一个都没有记住,只能更小声的说“随便吧”……
无论我的第一次肯德基经历会不会引起你的共鸣,都应该从这个例子中看出,强迫使用者记住每一个子类的名称和特性是不合适的,并且子类总是容易的变化的,比如现在CPU流行Intel、AMD,也许十年以后就流行龙芯、威盛,这时使用者的记忆就失去了价值,必须重新熟悉新的产品,可以使用简单类工厂来解决这个问题:
图:使用简单类工厂
SimpleFactory.java
public class SimpleFactory {
public static final int 便宜 = 0;
public static final int 贵 = 1;
public static final int 随便 = 2;
public static CPU getCPU(int s) throws NoSuchThingException{
switch (s) {
case 便宜:
return new AmdCPU();
case 贵:
return new IntelCPU();
case 随便:
return new IntelCPU();
default:
throw new NoSuchThingException();
}
}
public static Display getDisplay(int s) throws NoSuchThingException{
switch (s) {
case 便宜:
return new CRT();
case 贵:
return new LCD();
case 随便:
return new LCD();
default:
throw new NoSuchThingException();
}
}
}
有了这个SimpleFactory,当我们想得到一个CPU的子类实例时,就不需要记住子类的名称,只要传入常量 “便宜”或者“贵”就好(甚至还可以传“随便”),SimpleFactory会为我们实例化相应的子类对象。而且,即使子类发生了变化,比如以后龙芯取代了Intel,只需要改变SimpleFactory就可以了。
总之,一个简单工厂可以帮助我们实例化各种子类对象,使用简单工厂我们就不需要熟悉子类的具体结构,只需要了解父类就可以了,而且当子类产生变化时(增加或减少子类),我们的程序不会受到影响。
注意:使用SimpleFactory获取对象时,应该用CPU c = SimpleFactory.getCPU(贵)这样的语句,而不是IntelCPU c = SimpleFactory.getCPU(贵),否则就丧失了简单工厂的意义。由此还可以推出,在子类中不应当添加父类中没有定义的公有方法。
一个简单工厂一般有如下几个特征:
①.存在一个或多个产品簇(如本例的CPU产品簇,Display产品簇)
②.创建子类的方法其返回类型为父类类型(如getCPU方法返回CPU类型)
③.创建子类的方法一般需要传入一个标识(如getCPU方法传入一个整型)
简单工厂在Java类库中被大量使用,比如swing中的控件可以添加边框(Border),各种不用的边框子类实例可以通过简单工厂BorderFactory中的方法来得到。
如果希望在系统运行的过程中,一个类始终只存在一个实例时,就可以用单态模式。比如对一个程序而言,当前的显示屏、CPU、剪切板始终只有一个,应该用单态模式 来描述这些类。
在一个类中应用单态模式有以下两种常见的方式,称之为“懒汉式”和“饿汉式”。
懒汉式的Singleton饿汉式的Singleton
public class Test {
private Test() { }
private static Test instance = new Test();
public static Test getInstance() {
return instance;
}
}public class Test {
private Test() { }
private static Test instance = null;
public synchronized static Test getInstance() {
if (instance == null) {
instance = new Test();
}
return instance;
}
}
按照下面三个步骤就可以实现一个标准的Singleton:
①.将构造函数声明成私有(从语法上防止其他类实例化)
②.声明一个私有静态的自身对象
③.声明一个共有静态的方法,返回自身对象
上面的两端代码在2,3步略有不同,饿汉式可以确保当用户调用getInstance方法后才实例化自身对象,如果实例化的代价很昂贵的话,那么饿汉式可以避免无必要的实例化。但是在多用户的系统中可能会重复实例化,所以方法声明成了synchoronized,会影响一些效率。
单态模式在Java类库中的应用是java.lang.Runtime这个类。还有两个类很像,但不是单态模式:java.lang.Math和java.awt.Toolkit,原因是前者没有返回唯一的自身对象,后者返回的是子类对象。
第二招:简单工厂(Simple Factory)
简单工厂一般用来返回不同的子类对象。
举个例子,我想开一家店,卖各种电脑配件,包括CPU,显示器,内存,硬盘等,产品结构图如下:
图:产品结构
很容易看出,CPU是一个抽象类,有Intel的CPU和AMD的CPU两个子类,显示器则分为了电子管显示器和液晶显示器。好了,现在如果有顾客要来买CPU,该怎么处理呢?你不能直接给顾客一个CPU,因为CPU是抽象类,没有对象,必须要问“您需要什么样的CPU ?”,如果顾客答“我要Intel的”,就可以实例化一个IntelCPU对象给顾客了。
这个过程看上去理所当然,但是隐藏了一个问题,顾客必须清楚地知道存在IntelCPU这个子类,并了解它的特点,然而并非每个顾客都对自己要买的产品了如指掌。记得若干年前,我和大学同学准备去肯德基开开洋荤,第一次来这种“高档”的餐厅难免令人有些紧张,好不容易排到柜台前,我谨慎的对服务员说:“要两个汉堡”,服务员立刻问道:“请问要哪种汉堡?”,我立刻精神崩溃,啥,汉堡还分好几种?!我只得小声问道:“都有哪几种?”,服务员飞快的报出“香辣鸡腿堡、劲脆鸡腿堡、田园脆鸡堡……”,可怜的我因为紧张一个都没有记住,只能更小声的说“随便吧”……
无论我的第一次肯德基经历会不会引起你的共鸣,都应该从这个例子中看出,强迫使用者记住每一个子类的名称和特性是不合适的,并且子类总是容易的变化的,比如现在CPU流行Intel、AMD,也许十年以后就流行龙芯、威盛,这时使用者的记忆就失去了价值,必须重新熟悉新的产品,可以使用简单类工厂来解决这个问题:
图:使用简单类工厂
SimpleFactory.java
public class SimpleFactory {
public static final int 便宜 = 0;
public static final int 贵 = 1;
public static final int 随便 = 2;
public static CPU getCPU(int s) throws NoSuchThingException{
switch (s) {
case 便宜:
return new AmdCPU();
case 贵:
return new IntelCPU();
case 随便:
return new IntelCPU();
default:
throw new NoSuchThingException();
}
}
public static Display getDisplay(int s) throws NoSuchThingException{
switch (s) {
case 便宜:
return new CRT();
case 贵:
return new LCD();
case 随便:
return new LCD();
default:
throw new NoSuchThingException();
}
}
}
有了这个SimpleFactory,当我们想得到一个CPU的子类实例时,就不需要记住子类的名称,只要传入常量 “便宜”或者“贵”就好(甚至还可以传“随便”),SimpleFactory会为我们实例化相应的子类对象。而且,即使子类发生了变化,比如以后龙芯取代了Intel,只需要改变SimpleFactory就可以了。
总之,一个简单工厂可以帮助我们实例化各种子类对象,使用简单工厂我们就不需要熟悉子类的具体结构,只需要了解父类就可以了,而且当子类产生变化时(增加或减少子类),我们的程序不会受到影响。
注意:使用SimpleFactory获取对象时,应该用CPU c = SimpleFactory.getCPU(贵)这样的语句,而不是IntelCPU c = SimpleFactory.getCPU(贵),否则就丧失了简单工厂的意义。由此还可以推出,在子类中不应当添加父类中没有定义的公有方法。
一个简单工厂一般有如下几个特征:
①.存在一个或多个产品簇(如本例的CPU产品簇,Display产品簇)
②.创建子类的方法其返回类型为父类类型(如getCPU方法返回CPU类型)
③.创建子类的方法一般需要传入一个标识(如getCPU方法传入一个整型)
简单工厂在Java类库中被大量使用,比如swing中的控件可以添加边框(Border),各种不用的边框子类实例可以通过简单工厂BorderFactory中的方法来得到。