翻译TIPatterns--对象数量(Object quantity)

对象数量(Object quantity)

 

    这里描述的两种模式都可以单独用来控制对象的数量。

    单件(Singleton)实际上可以认为是对象池(Object Pool)的一个特例,但是对象池(Object Pool)的应用和单件(Singleton)是如此的不同,将二者区分开来对待是非常必要的。

 

单件(Singleton)

    单件(Singleton)提供一种方法使得某一特定类型存在一个,并且只能是一个对象。它可能是最简单的模式了。单件(Singleton)应用的一个重要方面是提供一个全局的存取点。单件(Singleton)是C里面全局变量的一个替代方法。

    除此之外,单件还常常提供注册(registry)和查找(lookup)的功能――你可以从单件那里找到其它对象的引用(find references to other objects)。

    单件(Singleton)可以在java库里找到,但是下面提供了一个更直接的例子。

//: singleton:SingletonPattern.java

// The Singleton design pattern: you can

// never instantiate more than one.

package singleton;

import junit.framework.*;

// Since this isn't inherited from a Cloneable

// base class and cloneability isn't added,

// making it final prevents cloneability from

// being added through inheritance:

final class Singleton {

          private static Singleton s = new Singleton(47);

          private int i;

          private Singleton(int x) { i = x; }

          public static Singleton getReference() {

                    return s;

          }

          public int getValue() { return i; }

          public void setValue(int x) { i = x; }

}

public class SingletonPattern extends TestCase {

          public void test() {

                    Singleton s = Singleton.getReference();

                    String result = "" + s.getValue();

                    System.out.println(result);

                    assertEquals(result, "47");

                    Singleton s2 = Singleton.getReference();

                    s2.setValue(9);

                    result = "" + s.getValue();

                    System.out.println(result);

                    assertEquals(result, "9");

                    try {

                             // Can't do this: compile-time error.

                             // Singleton s3 = (Singleton)s2.clone();

 

                    } catch(Exception e) {

                             throw new RuntimeException(e);

                    }

          }

          public static void main(String[] args) {

                    junit.textui.TestRunner.run(SingletonPattern.class);

          }

} ///:~

    单件模式的关键是防止用户以其它任何方式创建对象,而只能用你所提供的方式。所有的构造函数必须被声明为私有的(private),而且必须至少声明一个构造函数,否则编译器就会以package权限帮你创建一个默认的构造函数。

    在这一点上(at this point),你自己决定如何创建对象。上面的例子里,对象是静态(statically)创建的,但是你也可以等到客户端提出请求需要创建对象时才创建。不管是哪种情况,(创建的)对象必须以私有方式(privately)存储,而通过公有方法(public methods)来访问。上面的例子里,getReference()返回对单件对象的引用。剩下的接口(getValue()和setValue())是常规的类接口。

    另外,Java允许使用克隆(cloning)来创建对象。这个例子里,把这个类声明为final就是为了防止通过克隆方法创建对象。因为Singleton是直接从Object继承下来的,由于clone()是受保护的(protected)方法因而不能用来(复制对象),如果这么做就会导致编译时错误。

    但是,如果以public的方式继承了一个重载了clone()方法的类,并且实现了Cloneable接口的话,为了防止对象被克隆,就必须重载clone()方法并抛出一个CloneNotSupportedException异常。这一点在Thinking in Java 第二版的附录A里也讲到了。(你也可以重载clone()方法使它只返回this,但是这样做有一定的欺骗性,客户端程序员会想当然的认为他是在克隆(复制)那个对象,但实际上他处理的还是原来那个对象。)实际上,这么说并不确切,即使是上面所说的情况,你仍然可以使用反射(reflection)来调用clone()方法(真的是这样么?因为Clone()方法是受保护的(protected),所以我也不那么肯定。如果真是这样的话,那就必须得抛出CloneNotSupportedException 异常,这是保证对象不被克隆的唯一方法了。)

 

练习

1.  SingletonPattern.java 总是创建一个对象,即使这个对象从来不会被用到。请用延迟初始化(Lazy Initialization)的方法修改这个程序,使单件对象只在它第一次被用到的时候才创建。

2.  Create a registry/lookup service that accepts a Java interface and produces a reference to an object that implements that interface.

 

对象池(Object pool)

    并没有限制说只能创建一个对象。这种技术同样适用于创建固定数量的对象,但是,这种情况下,你就得面对如何共享对象池里的对象这种问题。如果共享对象很成问题得话,你可以考虑以签入(check-in)签出(check-out)共享对象作为一种解决方案。比如,就数据库来说,商业数据库通常会限制某一时刻可以使用的连接的个数。下面这个例子就用对象池(object pool)实现了对这些数据库连接的管理。首先,对象池对象(a pool of objects)的基本管理是作为一个单独的类来实现的。

//: 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);

 }

} ///:~

 

Exercises练习先不翻了

1. Add unit tests to ConnectionPoolDemo.java to demonstrate the problem that the client

may release the connection but still continue to use it.


 

目录

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值