管理好你的对象!

来源:互联网 发布:2017阿里年会马云演讲 编辑:程序博客网 时间:2024/04/30 13:02
     这篇日志相当有份量,是我个人工作了一年来对面向对象软件开发的最高度了,希望同行也能看一看,给点意见!
      面向对象语言的核心是对象,怎样有效的生成,管理对象是面向对象软件开发中标志代码质量的核心!许多初学者在刚刚接触面向对象软件时往往仍然在用面向过程的思路开发。过了一段时间,他们会逐步体会到继承和多态的好处,逐渐以面向对象的思路进行开发。可是许多时候,开发出的系统的性能往往不勘忍受。许多人认为这是从面向过程到面向对象带来的最大弊端:那就是类的膨胀!
       的确,从面向过程到面向对象的确是会牺牲一些性能,但绝对不会到不堪忍受的地步。究其原因,其实是因为许多时候由于代码质量的问题,往往系统在运行时会产生大量冗余的对象(实例)。因此如何有效的生成对象并有效的管理对象,就成了区分优秀代码和劣质代码的重要标准。
      本来我是想以这个星期改进的那个系统做示例的,但是为了避免惹上不必要的麻烦我还是重新举个新的例子来说明管理对象的重要性。
      考虑你要实现一个图书管理系统,那么在这个系统中你一定会把书抽象成一个类Book,Book中会有id,name,author等等属性,你一定还会想到管理员需要把特定的书放在特定的位置,书是放在书架上的,为了更好的抽象,你还需要一个书架类Bookshelf。并且在Book中还会有Bookshelf类这个属性,标志这本书是属于哪个书架类的。
       好了,现在在你的数据库操作实现类中一定有这样一个方法,传递进来一个bookId,查询数据库,将数据库中的数据封装成一个Book实例,并返回。请看以下的部分代码
        Class Book{
             String bookId;
             Bookshelf bookshelf;
             public Book(String bookId){
                     this.bookId = bookId;
             }
             public void setBookshelf(Bookshelf bookshelf){
                      this.bookshelf = bookshelf;
             }
         }
         }
         Class Bookshelf{
             String bookshelfId;
             public Book(String bookshelfId){
                     this.bookshelfId= bookshelfId;
             }
        }
         接下来是那个数据库操作的部分代码,假设已经从数据库中取得ResultSet需要的数据
         Book book = new Book(rs.getString("FBookId"));
         Bookshelf bookshelf = new Bookshelf(rs.getString("FBookshelfId"));
         book.setBookshelf(bookshelf);
         return book;
      这样做无疑是正确的,但是一个大雪的图书馆藏书几十w本是很正常的,因此有些极端的情况下可能整个系统同时会存在1w个Book对象而且由于,在封装book的同时,又new了Bookshelf所以另外又有1w个Bookshelf对象!试问,这样的系统怎么不会不堪忍受呢?如果服务器的内存过小,系统很可能就崩溃了!
      我们必须改进这段劣质的代码!也许你已经想到书架的个数一般是固定的,很少会加一个书架减一个书架。另外书架的个数肯定是有限的一个书架能放500本书很正常这样20w的书也最多需要400个书架。因此在封装Book的同时在new一个Bookshelf完全没有必要,这样做会使系统产生大量的一模一样的Bookshelf这就是冗余!
      那怎么做呢?我们需要有一个类在系统初始化的时候就生成了这些Bookshelf并维护他。由于书架一般不会变,因此这么做是可行的,否则为了增加一个书架,而频繁重启系统也是无法忍受的!书架类的生成还是由书架类自己来控制。请看下面改进的代码。
Class Bookshelf{
 
 private String bookshelfId
 
 
 private Bookshelf(String bookshelfId){
  this.bookshelfId = bookshelfId;
 }
 
 static Bookshelf parse(rs) throws SQLException{
  Bookshelf bookshelf = new Bookshelf(rs.getString("FBookshelfId");
  return bookshelf;
 }
}
Class BookshelfManager{
 private static BookshelfManager myself;
 
 private Map<String,BookshelfManager> bookshelves = new HahsMap<String,Bookshelf>();
 
 
 private BookshelfManager(){
  init();
 }
 
 private init(){
  ...
  while(rs.next()){
   bookshelves.add(Bookshelf.parse(rs));
  }
  ...
 }
 
 public BookshelfManager getInstance(){
  if(myself == null){
   myself = new BookshelfManager();
  }
  return myself;
 }
 
 public Bookshelf getBookshelf(String bookshelfId){
  return bookshelves.get(bookshelfId);
 }
}
      在这里,Bookshelf的构造函数已经是private的了,即其他类不能创建这个类的对象,那怎么办了?完全由BookshelfManager来负责Bookshelf对象的创建和维护。BookshelfManager本身是singleton的在唯一的一次初始化中他将调用init()这里其实是查数据库中对应书架的一些信息,每一个rs就是一条表示书架信息的结果集,之后会调用Bookshelf的parse方法,由Bookshelf自己创建新的Bookshelf对象并把它放入BookshelfManager所维护的一张存放所有Bookshelf的map中。然后我们就可以在数据库操作方法中这样写了。     
         Book book = new Book(rs.getString("FBookId"));
         Bookshelf bookshelf = BookshelfManager.getInstance().getBookshelf(rs.getString("FBookshelfId");
         book.setBookshelf(bookshelf);
         return book;
         这样事实上,所有的Bookshelf对象都由BookshelfManager对象管理了,任何其他类都不能创建Bookshelf对象。事实上,我们注意到Bookshelf必须暴露出创建对象的parse方法。由于Java没有友元(否则就把BookshelfManage设成Bookshelf的友元了,而parse也可以设成private了),所以我们需要建立一个包用来只存放Bookshelf和BookshelfManager。
         怎么样,是不是觉得很神奇啊?!负责写数据库操作的人根本不用负责对象的生成和管理,同时有更好的负责管理Bookshelf的BookshelfManager来做有效合理的管理!
         现在,代码质量已经有显著提高了?但是你会觉得我们不可能像BookshelfManager一样写一个BookManager类,然后初始化的时候建立一张map存放所有的书!因为书很可能有几十w本!所以还需要在数据库操作中,负责Book的创建!
         不存放所有的书就存放部分的书呗!如果让数据库操作类负责Book对象的创建,仍然是不合理的,同时存在1w本书的实例仍然不是个好办法!
         于是我们可以创建一个BookManager类,在这个类中也存放一张map表,但是map这张表中的元素的个数必须是固定,但是可以在初始化是配置大小的!当传递过来一个bookId时,它会先看原来的map中有没有这个id的Book如果没有,则判断map的大小有没有到达上限,如果达到,他会随机去除一条记录,然后新建对应于id的Book放到map中,如果没有达到上限,则直接创建并插入。如果map中已经有这个id的Book则直接返回。
          事实上这就是一个池(Pool)的概念,J2EE的应用服务器所支持的连接池,线程池等功能正式基于这个思想而创建的!由于动态map表的情况比较复杂,就不给出Book的改进代码和BookManager的代码了,下面给出最终的数据库操作的代码!
         Book book = BookManager.getInstance().getBook(rs);
         Bookshelf bookshelf = BookshelfManager.getInstance().getBookshelf(rs);
         book.setBookshelf(bookshelf);
         return book;
        这样所有其他功能就只生成引用而非对象了!对象都有相关的管理类管理,并有该类本身创建!这样一个图书馆系统的Book和Bookshelf对象在极端情况下也不会超过1k个了!
        这就是优质的代码!因此请管理好你的对象吧! 
 
 
原创粉丝点击