JAVA基础:Java程序的脏数据问题

发表于:2007-05-25来源:作者:点击数: 标签:java问题程序基础数据
脏数据(Out-of-date data),指过时的数据。 如果在您的 Java 程序中存在脏数据,将或多或少地给软件系统带来一些问题,如:无法实时地应用已经发生改变的配置,软件系统出现一些莫名其妙的、难以重现的、后果严重的错误等等。尽量避免脏数据的存在是非常有价

脏数据(Out-of-date data),指过时的数据。

  如果在您的Java程序中存在脏数据,将或多或少地给软件系统带来一些问题,如:无法实时地应用已经发生改变的配置,软件系统出现一些莫名其妙的、难以重现的、后果严重的错误等等。尽量避免脏数据的存在是非常有价值的。本文希望能在这方面给同行们一点帮助。

Fragment 1. 缓存技术的脏数据问题

  /**
    * A report printer is used to print a report.
    *
    * @version 1.0 9/9/2003
    * @author Bill
    */
   public class ReportPrinter {
   /**
       * Constructs a ReportPrinter instance.
   */
      public ReportPrinter() {
         // do something...
   }

   /**
       * Prints a printable.
  *
       * @param printable the specified printable object
   */
      public void print(Printable printable) {
         Graphics g = getGraphics();
         g.setFont(getReportFont(printable.getFont());

         printable.print(g);
   }

   /**
       * Returns the corresponding report font of a java font.
  *
       * @param javaFont the specified java font
       * @return the corresponding report font
   */
     private Font getReportFont(font javaFont) {
         Font reportFont = fontMap.get(javaFont);

         if(reportFont == null) {
           reportFont = loadFont(javaFont);
           fontMap.put(javaFont, reportFont);
      }

         return reportFont;
   }

   /**
      * Loads the corresponding report font of a java font.
  *
       * @param javaFont the specified java font
       * @param the corresponding report font
   */
      protected static Font loadFont(Font javaFont) {
         Font reportFont = null;

         // do something...

         return reportFont;
   }

   /**
       * The font map(java font->report font).
   */
     private static HashMap fontMap = new HashMap();
  }

  Fragment 1中,由于装载一个java font所对应的report font开销较大,使用了缓存技术来避免这种开销。这是一种常见的提高性能的方式,而且在一般情况下运行良好。但是Fragment 1的设计与实现可能是不完备的,因为极有可能一个java font所对应的report font在系统启动之后发生变化,在这种变化发生之后,只有重启软件系统才能装载之,这常常是最终用户的抱怨之一。更可怕的是,类似的这种脏数据的存在还可能带来其它严重的、无法想象的后果。

  如何避免使用缓存技术所带来的脏数据问题呢?

  在设计、实现和测试时,应该清晰定义缓存数据的更新:
  i. 不考虑缓存数据的更新,重启软件系统是一种必要的方式;
  ii. 不考虑缓存数据的更新,缓存数据不可能成为脏数据(但在软件系统中,往往“不可能”会在一次又一次的重构之后变为“可能”);
  iii. 考虑缓存数据的更新,当源数据变化时,实时更新缓存数据。

Fragment 2. Singleton模式的脏数据问题

  /**
    * A storage usage handler is used to query the storage usage of users.
    *
    * @version 1.0 9/9/2003
    * @author Bill
    */
   public class StorageUsageHandler {
   /**
       * Returns a StorageUsageHandler instance.
  *
       * @return the single StorageUsageHandler instance
   */
      public static StorageUsageHandler getStorageUsageHandler() {
         if(handler == null) {
          handler = new StorageUsageHandler();
      }

         return handler;
   }

   /**
       * Constructs a StorageUsageHandler instance.
   */
     private StorageUsageHandler() {
        users = Context.getAllUsers();
   }

   /**
       * Returns the storage sizes of all the users.
  *
       * @return the storage sizes
   */
      public long[] getSizes() {
         long sizes[] = new long[users.size()];

        for(int i = 0; i < users.size(); i++) {
           sizes[i] = getOneSize(users.get(i));
    }
   }

   /**
       * Returns the storage size of a user.
  *
       * @param user the specified user
       * @return the storage size
   */
      protected long getSize(User user) {
         // do something...

       return 0;
   }

   /**
       * The StorageUsageHandler singleton.
   */
     private static StorageUsageHandler handler;

   /**
       * The users.
   */
     private List users;
  }

  您看出了问题所在吗?

  Fragment 2中,由于没有必要次次实例化StorageUsageHandler而带来不必要的开销,采用了Singleton模式以保证StorageUsageHandler只被实例化一次。

  在实例化SotrageUsageHandler时,StorageUsageHandler的类成员users将被赋值。由于不存在任何对users重新赋值的方法,一直驻留在软件系统中的users将不会发生任何变化。在软件系统启动之后,增加、删除或修改用户的操作经常会发生,而一旦发生这类操作,users就成为了脏数据,Fragment 2将无法正常工作。

  如何避免使用Singleton模式所带来的脏数据问题呢?

  对于Singleton类的类成员:
  i. 对于与Singleton类外部无依赖关系的类成员,不存在这种问题;
  ii. 对于依赖于Singleton类外部的类成员,且该类成员不存在更新机制,最好是将其去掉,需要时从Singleton类外部直接获取;如果这种办法不可行,应提供机制以确保在使用该类成员之前,该类成员已经被更新过。

Fragment 3. 类使用的脏数据问题

  /**
    * A storage usage handler is used to query the storage usage of users.
    *
    * @version 1.0 9/9/2003
    * @author Bill
    */
   public class StorageUsageHandler implements AdminHandler {
   /**
       * Constructs a StorageUsageHandler instance.
   */
     private StorageUsageHandler() {
        users = Context.getAllUsers();
   }

   /**
       * Returns the storage sizes of all users.
  *
       * @return the storage sizes
   */
      public long[] getSizes() {
         long sizes[] = new long[users.size()];

        for(int i = 0; i < users.size(); i++) {
           sizes[i] = getOneSize(users.get(i));
    }
   }

   /**
       * Returns the storage size of a user.
  *
       * @param user the specified user
       * @return the storage size
   */
      protected long getSize(User user) {
         // do something...

       return 0;
   }

   /**
       * Displays the storage usage of users.
  *
       * @param req the http servlet request
       * @param res the http servlet response
  *
       * @throws IOException
       * @throws ServletException
   */
      public void process(HttpServletRequest req, HttpServletResponse res)
         throws IOException, ServletException {

         res.setContentType("text/html");
         res.setHeader("Cache-Control", "no-cache");
         res.setHeader("Pragma","no-cache");
         res.setDateHeader("Expires", 0);

         PrintWriter writer = new PrintWriter(res.getOutputStream());
         long sizes[] = getsizes();
         writer.println("");
         writer.println("

原文转自:http://www.ltesting.net

评论列表(网友评论仅供网友表达个人看法,并不表明本站同意其观点或证实其描述)