对象数量(Object quantity)
这里描述的两种模式各自用于控制对象的数量。单态确实能够被看作对象池(Object Pool)的一个特别的例子。但是对象池的应用独特于单态模式,我们分别的来看待它。
单态模式(The Singleton)
也许最简单的设计模式是单态(The Singleton),它是只提供一个特定类型对象的方式,java类库里面有应用,这里给了一个更直接的例子:
单态模式的关键在于阻止客户端程序用别的方式来创建对象,除非使用你提供的方式。你必须声明构造函数为private,并且你必须创建一个构造函数以阻止编译器赋给你一个默认的构造函数。(它将作为友元来被创建)
在这点上,你决定怎样去创建对象。这里,他被静态的创建,你也能够在客户端应用程序需要时动态的创建。无论怎样,对象必须是被私有的存贮,你提供public的方法来访问。getReference( )方法提供单态对象的引用,其余的接口(getValue() 和setValue()) 是正常类的接口。
Java也允许通过克隆(clone)来创建对象。本例中final class来阻止克隆,因为singleTon直接从Object来继承,clone()方法为protected, 所以它不能使用(如果用的话会产生编译器错误)。然而,当你从一个已经重写了clone() 方法(并且这个方法为public)的类继承,并且实现了cloneable这个接口时,阻止clone()的方式是重写clone(),并且抛出一个CloneNotSupportedException的异常。(你也可以重写clone(),并且简单的return this,但是这是欺骗行为,客户端程序会认为他们克隆了这个对象,但是事实上他们处理的还是原来那个对象)。
练习
1. SingletonPattern.java 即使未被使用,也总是创建一个对象,修改这个程序为懒汉初始化,当singleTon对象被第一次调用时才被创建.
2. 用SingletonPattern.java 作为起点,管理它自己固定数量的对象.假定这个对象为数据库连接对象,任何时候你只有一个许可应用这些固定的对象.
对象池(Object Pool)
记住,你并没被限制去创建仅仅一个对象。这也是创建有限的对象池的一个技巧。在这种情况下,你可以使用池中的共享对象。由此,你也可以创建一个共享对象的check-out 和check-in的解决方案。
作为一个例子,考虑下数据库。商业数据库经常限制在任何时间内你能用的连接数。这里是一个管理连接池对象应用的一个实现。首先,管理连接池对象的基本概念是作为一个分离的类来实现的。
//: singleton:PoolManager.java
package singleton;
import java.util.*;
public class PoolManager {
private static class PoolItem {
boolean inUse = false;
Object item;
PoolItem(Object item) { this.item = item; }
}
private ArrayList items = new ArrayList();
public void add(Object item) {
items.add(new PoolItem(item));
}
static class EmptyPoolException extends Exception {}
public Object get() throws EmptyPoolException {
for(int i = 0; i < items.size(); i++) {
PoolItem pitem = (PoolItem)items.get(i);
if(pitem.inUse == false) {
pitem.inUse = true;
return pitem.item;
}
}
// Fail early:
throw new EmptyPoolException();
// return null; // Delayed failure
}
public void release(Object item) {
for(int i = 0; i < items.size(); i++) {
PoolItem pitem = (PoolItem)items.get(i);
if(item == pitem.item) {
pitem.inUse = false;
return;
}
}
throw new RuntimeException(item + " not found");
}
} ///:~
//: singleton:ConnectionPoolDemo.java
package singleton;
import junit.framework.*;
interface Connection {
Object get();
void set(Object x);
}
class ConnectionImplementation implements Connection {
public Object get() { return null; }
public void set(Object s) {}
}
class ConnectionPool {
// A singleton
private static PoolManager pool = new PoolManager();
public static void addConnections(int number) {
for(int i = 0; i < number; i++)
pool.add(new ConnectionImplementation());
}
public static Connection getConnection() throws PoolManager.EmptyPoolException {
return (Connection)pool.get();
}
public static void releaseConnection(Connection c) {
pool.release(c);
}
}
public class ConnectionPoolDemo extends TestCase {
static {
ConnectionPool.addConnections(5);
}
public void test() {
Connection c = null;
try {
c = ConnectionPool.getConnection();
} catch (PoolManager.EmptyPoolException e) {
throw new RuntimeException(e);
}
c.set(new Object());
c.get();
ConnectionPool.releaseConnection(c);
}
public void test2() {
Connection c = null;
try {
c = ConnectionPool.getConnection();
} catch (PoolManager.EmptyPoolException e) {
throw new RuntimeException(e);
}
c.set(new Object());
c.get();
ConnectionPool.releaseConnection(c);
}
public static void main(String args[]) {
junit.textui.TestRunner.run(ConnectionPoolDemo.class);
}
} ///:~
练习
1. 添加单元测试到 ConnectionPoolDemo.java 文件中论证这个问题:客户端也许会释放这个连接在仍然使用它的时候。omencathay 译
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/25966/viewspace-53314/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/25966/viewspace-53314/