回归

蓦然回首,那人却在灯火阑珊处

  BlogJava :: 首页 :: 联系 :: 聚合  :: 管理
  4 Posts :: 2 Stories :: 12 Comments :: 0 Trackbacks

2007年6月5日 #

 

         前些時工作忙,中間停頓一段時間,今天繼續。向關注這里的文章的博友們表示抱歉。
         今天說說一個簡單的模式,迭代器模式(Iterator),他屬于行為模式中的一種。

         [形成]

         在Java程序中,在輸出List類型的對象時候,出現最多的程式塊就是:
         

1     for (int i = 0 ;i<list.size; i++){
2         XXX x = (XXX)list.get(i);
3     }

 

其中list 是List 類型,里邊放著若干個XXX類型的對象。
這種 方式是采用i++遞增的方式來遍歷list中的所有對象來進行相關操作。對于設計模式,把i的功能抽象劃的結果就是:Iterator Pattern

Iterate 中文的意思是“迭代,反復”,Iterator 的意思可以理解為“迭代器”。

       [代码示例]
        示例程式是把書(Book)放到書架上(BookShelf)上,并依次輸出書名。
         
         程式列表
   
名稱 說明
Aggregate 表示已聚合的接口
Iterator 執行遞增,遍歷的接口
Book 表示書籍的類
BookShelf 表示書架的類
BookShelfIterator 掃描書架的類
Main 測試用的類

   
          










[UML图]






      [示例代码和类的诠释]

1 package Iterator;
2 
3 import java.util.Iterator;
4 
5 public interface Aggregate {
6     public abstract Iterator iterator();
7 }
8 

Aggregate 接口:
     該接口只聲明了一個方法,建立一個可以對應聚合的Iterator.,當需要遍歷某個聚合對象時,調用Iterator方法可以建立一個實現Iterator接口的類的對象實例。

1 package Iterator;
2 
3 public interface Iterator {
4     public abstract boolean hasNext();
5     public abstract Object next();
6 }
7 

Iterator 接口:
這是該模式的核心接口,Iterator接口執行元素的遞增,具有循環遍歷的功能。Iterator的接口的方法因需要而定,我們可以初步確定接口方法:
hasNext() :是檢查有沒有“下一個元素”,返回boolean.(有,返回true,,無,返回false)
next();取得“下一個元素”,同時把取對象的指針指向下一個元素,以便下次調用next方法的時候確實能取到下一個元素。這些具體實現還得看具體的實現Iterator接口的類的實現才知道

 1 package Iterator;
 2 
 3 public class Book {
 4     private String name = "";
 5 
 6     public Book(String name) {
 7         this.name = name;
 8     }
 9 
10     public String getName() {
11         return name;
12     }
13 }
14 

Book 類:
表示書籍的類,比較簡單,通過getName方法得到書的名字,書名是以構造函數初始化對象的時候用參數來字號定。


 1 package Iterator;
 2 
 3 public class BookShelf implements Aggregate{
 4     private Book[] books;
 5     private int last = 0;
 6     
 7     public BookShelf(int maxsize){
 8         this.books = new Book[maxsize];
 9     }
10         
11     public Book getBookAt(int index){
12         return books[index];
13     }
14     public void appendBook(Book book){
15         this.books[last] = book;
16         last++;
17     }
18     
19     public int getLength(){
20         return last;
21     }
22     public Iterator iterator(){
23         return new BookShelfIterator(this);
24     }
25 }
26 


BookShelfl類:
     該類是表現書架作用的類,保證實現Aggregate接口所聲明的Iterator方法里返回實現Iterator接口的實例。如果需要遍歷書架上的書,調用iterator方法。books數組存放的對象就是book,書架大小可以在一開始建立時設置大小,當然我們可以不用數組而采用java.util.Vector,就可以往書架上放超過指定數量的書籍。


 1 package Iterator;
 2 
 3 public class BookShelfIterator implements Iterator{
 4     private BookShelf bookShelf;
 5     private int index;
 6     public BookShelfIterator(BookShelf bookShelf){
 7         this.bookShelf = bookShelf;
 8         this.index =0;
 9     }
10     
11     public boolean hasNext(){
12         if(index < bookShelf.getLength()){
13             return true;
14         }else{
15             return false;
16         }
17     }
18     
19     public Object next(){
20         Book book = bookShelf.getBookAt(index);
21         index++;
22         return book;
23     }
24 
25 }
26 

BookShelfIterator類:

      字段bookShelf指定BookShelfIterator所要掃描的書架,而index字段則是指向目前該書的下標。
      構造函數把傳過來的BookShelf對象實例儲存在bookShelf字段,將index設置為0.
      實現的hasNext方法判斷是否有下一本書的標準是根據index是否小于書架上書籍的數量(表達式bookShelf.getLength()的值)來判斷。
      next方法返回目前該書,并進入到“下一個”。兩步:第一步先把取得當面的書籍保留在book變量,然后把循環變量推到“下一個”。


 1 package Iterator;
 2 
 3 public class Main {
 4     /**
 5      * @param args
 6      */
 7     public static void main(String[] args) {
 8         BookShelf bookShelf = new BookShelf(3);
 9         bookShelf.appendBook(new Book("book1"));
10         bookShelf.appendBook(new Book("book2"));
11         bookShelf.appendBook(new Book("book3"));
12         Iterator it  = bookShelf.iterator();
13         while(it.hasNext()){
14             Book book = (Book)it.next();
15             System.out.println(" "+book.getName());
16         }
17     }
18 
19 }
20 

Main類:
     1.先放三本書上架
      2.通過調用書架的iterator方法得到迭代器,來進行循環遍歷
      3.循環遍歷書籍,取出書,打印出書的名字。


示例程序的执行结果 book1
 book2
 book3

回顧一下,在迭代器模式中幾個重要“角色”:
     迭代器: 定義了訪問和遍歷元素的接口 ,它定義了能否取得下一個元素信息的的hasNext方法和取得下一個元素的next方法
    具體的迭代器:實現了迭代器的接口,如本例的BookShelfIterator,掌握遍歷時的重要信息。
    聚合:定義了建立了Iterator的接口。如本例的:Aggregate接口,定義了Iterator方法
   具體聚合:實現了聚合的所定義的接口,如本例的BookShelf,它實現了Iterator方法。


      [拓展思考]
       有人回想,干嘛搞這么麻煩,用一個for不就是可以遍歷數組或List碼?思考一下迭代器的結構。Iterator是把定義和實現分開

        while(it.hasNext()){
                           Book book = (Book)it.next();
                        System.out.println(" "+book.getName());
          }
      這里我只調用了Iterator接口的hasNext和next方法,并沒有調用BookShelf實現遍歷是需要的方法,如:getBookAt()。這里的while不會收到BookShelf的實現影響。
      假設這里我們不采用數組來管理BookShelf,而采取與Java.util.Vector來管理。無論BookShelf的如何修改,都Main測試程序里無需修改任何程序就可以運行,這就是設計模式的優勢。設計模式是為了提高類的服用率,如果把一個零件修改了,就不想要修改其他使用了改零件的部分。

 
posted @ 2007-07-27 15:22 回归 阅读(1177) | 评论 (2)编辑 收藏

      现在大多数Java软件工程师面试都会问到这个问题:什么是单例模式(Singleton),能否写出单例模式的示例代码?单例模式是Gof中23个模式中最简单最容易入门的模式,学习它我们能更理性的感知模式的意义.

     [形成]

      Singleton Pattern 为什么会出现?在我们软件开发和架构中,经常遇到这样的情形:我们需要一个类只能且仅能产生一个实例..比如表示一台计算机的类,表示系统设定的类或者是表示窗口的类,还有为了节约资源,只让产生一个实例..
     
      如何构造这种情形?Singleton模式给我一个方案:


     [代码示例]
      
      程序列表
   

名称

说明

Singleton

只有一个对象实例的类

Main

测试用的类



      [UML图]
   
      

[示例代码和类的诠释]

 1 package singleton;
 2 
 3 public class Singleton {
 4     private static Singleton singleton = new Singleton();
 5 
 6     private Singleton() {
 7         System.out.println("Create instance...");
 8     }
 9 
10     public static Singleton getInstance() {
11         return singleton;
12     }
13 }
14 


          Singleton  Class:
            
            1.该类只能产生一个对象实例

            2.把该类的的singleton属性设定为static再以Singleton;类的对象实例进行初始化,这个初始化的过程仅加载Sington类的时候调用一次.(Line4) 

            3.把Singleton 类的构造函数限定为private,目的是为了防止从非Singleton类(其他类)调用构造函数来产生实例,如果通过new方式来产生Singleton实例,会出现编译错误.这样做是为了保险己见.(Line6) 

            4.要得到Singleton实例的唯一方法就是调用类静态方法getInstance().这个名字可以随便取,只要方便理解就行.(Line 10) 

 1 package singleton;
 2 
 3 public class Main {
 4 
 5     public static void main(String[] args) {
 6         System.out.println("Start");
 7         Singleton obj1 = Singleton.getInstance();
 8         Singleton obj2 = Singleton.getInstance();
 9         if(obj1 == obj2){
10             System.out.println("obj1和obj2是同一個對象實例");
11         }else{
12             System.out.println("obj1和obj2不是同一個對象實例");
13         }
14         System.out.println("End");
15     }
16 }
17 


       Main Class
        1.该类是测试程序.
        2.程序通过getInstance()方式产生两个obj1和obj2实例.(Line 7,Line 8)
        3.通过ojb1= =ojb2表达式来确定两个对象是否相同,判定是否产生了Singleton的第二个示例.(Line9-12)
 

示例程序的执行结果
Start
Create instance...
obj1和obj2是同一個對象實例
End

         执行结果含义:
                1. 的确如此,obj1和obj2是Singleton类的同一个且唯一的对象实例. 
                2.当程序执行后,第一次调用getInstance的时候会初始化Singleton类,同时也会初始化static字段,也同时产生产生了一个唯一对象实例.




      [拓展思考]
   
如下的另一一个单例模式的程序有什么隐患?

 1 package singleton;
 2 
 3 public class Singleton2 {
 4     
 5     private static Singleton2 singleton = null;
 6     
 7     private Singleton2(){
 8         System.out.println("已產生對象實例");
 9     }
10     public static Singleton2 getInstance(){
11         if(singleton == null){
12             singleton = new Singleton2();
13         }
14         return singleton;
15     }
16 
17 }
18 

    [解答]
当多线程同时调用Singleton2.getInstance()方法时,可能会产生多个对象实例,例如
public class Main extends Thread{

    
public static void main(String[] args) {
        System.out.println(
"Starts.");
        
new Main("A").start();
        
new Main("B").start();
        
new Main("C").start();
        System.out.println(
"End.");
    }

   
    
public void run(){
        Singleton2 obj 
= Singleton2.getInstance();
        System.out.println(getName()
+": obj ="+obj);
    }

    
    
public Main(String name){
        
super(name);
    }

}




public class Singleton2 {
    
private static Singleton2 singleton2 = null;
    
private Singleton2(){
        System.out.println(
"已产生对象实例");
        solwDown();
    }


    
public static Singleton2 getInstance(){
        
if(singleton2 == null){
            singleton2 
= new Singleton2();
        }

        
return singleton2;
    }

    
     
private  void solwDown(){
         
try{
             Thread.sleep(
1000);
         }
catch(InterruptedException e){
             e.printStackTrace();
         }

     }

}


执行结果:

Start.
End.
已产生对象实例.
已产生对象实例.
已产生对象实例.
B: obj = Singleton2#2a9348
C: obj = Singleton2#b91134
A: obj = Singleton2#e343l12

(#替换为@)

之所以会知道这种情况是因为if(singleton = = null){ singleton = new Singleton2(); }判断不够严谨的导致。
利用: singleton == null 判断为空后去执行new Singleton2()之前,可能会有其他线程来抢先判断表达式singleton == null,从而又执行一遍创建实例的操作。

解决办法:
给getInstance()方法添加Synchronized修饰符,即可修改成线程安全严谨的单例模式。

public class Singleton2 {
    
private static Singleton2 singleton = null;

    
private Singleton2() {
        System.out.println(
"已产生对象实例");
        solwDown();
    }

    
public static synchronized Singleton2 getInstance() {
        
if (singleton == null) {
            singleton 
= new Singleton2();
        }
        
return singleton;
    }

    
private void solwDown() {
        
try {
            Thread.sleep(
1000);
        } 
catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

posted @ 2007-06-08 11:36 回归 阅读(1190) | 评论 (7)编辑 收藏

      [UML漫谈]
      话说"工欲善其工需利其器",有了好的工具,好的表达方式,能给我们的工作变得简单而优雅.

      为了更好的讲解设计模式,方便理解,需要运用一种建模设计语言----UML.

       UML(UML:Unified Modeling Language),即统一建模语言,用来对软件密集系统进行描述、构造、视化和文档编制的一种语言.这是概念,不好理解.

       UML的作用,打个比方:一段描写迷人海滩风景的文字和一幅描绘海滩风景的油画,去看这两件东西的人,有的人可能能读懂文字(可能是特定的语言),有的不认字,所以并不是所有的人能看懂文字表达的内容,但是所有的人都能读懂油画所表现出来的含义.油画表达内容的直接,形象,丰富特性就类型UML在描叙软件结构过程中的作用.

       在软件项目中,一般有几个角色:用户(User),架构设计师(orPM, SA),程序员(PG)

         用户:
               也许不懂计算机,也不懂编程语言,但是懂行业业务,该软件的功能需求.

       程序员
              懂计算技术,懂编程语言.但是不太了解行业逻辑.需要把客户的业务应用需求转变为程序代码,
         
       架构设计师
               资深的行业架构设计师应该具有一定的行业知识,既能听懂客户的业务需求,又能知道怎么告诉程序员去用代码实现.

         架构设计师在前两者交流中起到承前启后的"中间体"作用.UML就是采用图形化的形式来表达架构和设计.成为了建模设计的通用的设计标准..


UML图让信息交流变得简单

      
     [UML基础]
      

   此处只介绍帮助理解设计模式的UML基础,具体其他的UML图示需要参考具体的讲解UML的书籍.
    1.类的层级关系
          UML中的类图是一种可表示一组类,对象实例和接口之间的静态关系图.




如图的UML类图表达了上面代码的含义,

类之间的关系有四种:依赖,泛化,实现聚集,组成.具体的UML实例可以参UML基础.

2.接口和实现

      实现接口的UML示例如下:


interface Printable {
    
abstract void print();
}
public class PrintClass implements Printable {

    
public void print() {
        
// how to print
    }

}

接口,抽象,实现,继承在设计模式中被广泛的使用,这也是OOD的优势所在.美妙所在.

这里只举出了几个简单情形,让大家有个感性的了解,具体的情形在说具体的设计模式的时候在针对性的说明,先不用弄那么多,那么杂,能开始下一步就足够.

类之间的关系

类之间的关系有5种,关联 依赖 聚集 泛化 实现
posted @ 2007-06-08 09:53 回归 阅读(1054) | 评论 (0)编辑 收藏

                                                                                 原创作者:阿风 
                                                                                  日期:2007-06-05   

        首先说说写这系列的文章的想法,目的在于:
        1.自己也在研习设计模式,通过在自我总结的过程中,希望能多设计模式多一点深刻理解
        2.希望给看到这系列文章的朋友一点对设计模式学习的帮助,特别是对设计模式的初学者能起到"引进门"的效果,
        如果以上的作用能起到哪怕一点,我也欣闻而笑了.

       设计模式(Design Patterns)是什么?为什么会出现设计模式?做过开发项目的朋友可能都遇到过,一个问题会在一个项目或者多个项目中重复出现,而相应的解决方案都是类似相同,相应代码的实现也是大同小异,为什么我们不能复用这些解决方案,或者说我们是否能修改或重新构建一下设计架构来使得重复的代码更少,结构更合理?  当然,这些是可行且有必要的. 此时设计模式的出现让我们茅舍顿开.

       说到设计模式,不得谈一本书<Design Patterns:Element of Resuable Object-Oriented Software),作者是GoF,实际是三个人合著的.之所以提到这本书,因为这本书的经典在于详细阐述了23种在软件开发过程中运用广泛的"模式",这一个理念的提出,给面向对象设计(OOD)注入了新的血液,体现出OOD超越面向过程设计的优势所在,从此让程序员看待代码有了"哲学的眼光"..

       就像这本书定义的模式:每个模式描述了一个在我们周围不断重复和发生的问题,以及该问题解决方案的核心,这样你就能一次又一次使用该方案而不必做重复劳动.

        至此,设计模式的意义已经凸现,设计模式给我们的启发又是什么?的确,每个经典的设计模式体现出了大师的精湛思想,我们需要从中得到的启发是能否"举一反三",在我们每一次的软件设计和开发中融入这些经典模式,让软件设计得更易理解,更易拓展,更易维护.这是设计模式给后人的最大启示.
         
        经典的设计模式給我的启示应该是個思想,而不是固定的那幾個模式,具体的软件项目或软件产品,會有不同情形,我们应该依据具体的情況合理运用模式思想,设计模式只是"招式"套路,要做到"无招胜有招",需要具体的情形分析,并非一定要套用所谓的模式,但是原则是不变的,"让软件易理解,易拓展,易维护".

         把语言特性和设计模式有机结合起来,对于程序员来说是一个成长的标志点也是转折点,希望此文能对所有程序员有所帮助.
 

          用心去写文章是件不容易的事情,需要坚持和执著,既然开始,就应该坚持到底..

        这个系列的文章主要是从GoF的归纳的23种设计中挑选十来个在软件项目中常用和运用的设计进行讲叙,讲叙风格应该是简单,深入浅出,思路和代码相结合.

         该系列文章要讲述的几个经典设计模式:(暂定)
            

创建模式(Creational Patterns)
      * Singleton ------单例                                * Factory  Method -----工厂方法 



结构模式(Structural Patterns)
      * Adapter ------适配器                              * Facade -----外观  

      * Decorator ------装饰                               * Proxy -----代理

    

  
行为模式(Behavioral Patterns)
      * Iterator------迭代器                              * Template Method-----模板方法  

      * Observer ------观察者                          * Strategy -----策略



        实现语言采用Java,是设计模式让OOD成为软件开发历史上的光辉更加绚烂.
    
       有人说:开始总是好的.所以,赶紧开始把.
        
posted @ 2007-06-05 11:30 回归 阅读(990) | 评论 (3)编辑 收藏