呆羊在曬太陽  
          公告
          • Y:哦,是你呀。
            X:我現(xiàn)在正在忙。
            Y:忙什么?
            X:呵呵,今天出太陽了,我把錢搬出來曬一曬。
            ***********************
            abc
            小叉
            很高興能結(jié)識大家!
            ***********************
          日歷
          <2006年1月>
          25262728293031
          1234567
          891011121314
          15161718192021
          22232425262728
          2930311234
          統(tǒng)計
          • 隨筆 - 164
          • 文章 - 2
          • 評論 - 196
          • 引用 - 0

          導航

          常用鏈接

          留言簿(7)

          隨筆分類(158)

          文章分類(2)

          相冊

          log

          搜索

          •  

          積分與排名

          • 積分 - 71044
          • 排名 - 778

          最新評論

          閱讀排行榜

           

          1. 簡介和簡單的實現(xiàn)

          IAdapteable實際上在Eclipse早期版本中不叫這個名字,它原來的名字叫做IExtensible,顧名思義就是可以擴展的意思,后來為了更能突出是由一個類配適到一個接口這么一種機制,所以改名為IAdaptable。
          這個接口有什么用呢,其實說白了,就是提供一個類型的轉(zhuǎn)換機制。比如下面這段代碼:

          Class IAdaptable  
          public interface
           IAdaptable  {
           
          public
           Object getAdapter(Class clazz);
          }

          Class ListAdapter
          public class ListAdapter extends ArrayList implements
           IAdaptable {
           
          public
           Object getAdapter(Class clazz) {
            
          if(clazz == Vector.class
          ){
             Vector v 
          = new Vector(this
          .size());
             v.addAll(
          this
          );
             
          return
           v;
            }
            
          return null
          ;
           }
          }


          ListAdapter類繼承了ArrayList,并且實現(xiàn)了IAdaptable接口,我們 想要將它轉(zhuǎn)化成Vector類型對象,于是在getAdapter方法中我們判斷傳入?yún)?shù)類型,如果是Vector類那么就新生成一個Vector對象,將ArrayList中的值全部賦給它,并返回。

          這樣,我們就可以寫出以下代碼:

          ListAdapter list = new ListAdapter();
            Vector v 
          = (Vector) list.getAdapter(Vector.class);


          ArrayList會返回Vector對象,這個對象是ArrayList的一個另外一種類型的副本。

          2.一個Swing程序

          讀者會問:這有什么用啊,不就簡單轉(zhuǎn)化一下麼。其實說實話,從上面的代碼來看確實沒什么用,但是如果我們換一個場景試試。

          寫這么一個Swing程序:有一個對話框,其中它有一個ComboBox和一個Table,ComboBox中存放的是一個名為Person類型的對象,當ComboBox的選項發(fā)生改變的時候,就在Table上顯示它的屬性,我們假設(shè)這個Swing程序已經(jīng)在某個項目中開始實施,并且其界面布局不易更改。

          看看代碼:

          Class person
          public class
           Person {
           
          private String name = "name"
          ;
           
          private String age = "23"
          ;
           
          private String sex = "male"
          ;
           
           
          public
           Person(String name){
            
          this
          .setName(name);
           }
           
           
          public
           String getName() {
            
          return
           name;
           }
           
           
          public void
           setName(String name) {
            
          this.name =
           name;
           }
           ……
          }

          UI類的部分代碼:

          {
                 table 
          = new
           JTable();
                 
          this
          .getContentPane().add(table);
                 table.setBounds(
          2182171248
          );
                }
                {
                 ComboBoxModel jComboBox1Model 
          = new
           DefaultComboBoxModel(
                  
          new Object[] { new Person("rEloaD"), new Person("b"
          ) });
                 comboBox 
          = new
           JComboBox();
                 
          this
          .getContentPane().add(comboBox);
                 comboBox.setModel(jComboBox1Model); 
                 comboBox.addActionListener(
          new
           ActionListener(){
                           
          public void
           actionPerformed(ActionEvent e){
                               JComboBox comboBox 
          =
          (JComboBox)e.getSource();
                               Person p 
          =
           (Person)comboBox.getSelectedItem();
                               TableModel jTable1Model 
          = new
           DefaultTableModel(
                                               
          new String[][] { { "Name"
          , p.getName() },
                                                                 { 
          "Sex"
          , p.getSex() },
                                                                { 
          "Age"
          , p.getAge() }},
                                               
          new String[] { "Column 1""Column 2"
           });
                               table.setModel(jTable1Model);
                                }
                            });

                }


          ClassDiagram2.JPG



           運行我們的代碼,會發(fā)現(xiàn)效果還可以,每當我們選項改變的時候,Table就如同一個屬性欄一樣,改變著自己的內(nèi)容:

          jframe.JPG



          3.需求變更

          OK,問題來了。我寫完這段代碼后,組長告訴我,現(xiàn)在我們有一個新的需求,就是Combox中不僅僅有Person類型存在,而且還有一些貨物(Product)類型,也就是說,我的table顯示屬性不能光針對Person這個類型了,還需要顯示Product的屬性。

          我心里罵了句:早TMD干嘛了,都快交活兒了才告訴我。

          無奈,我新增加了一個Product類型,然后更改了ActionListener中的部分代碼:

          JComboBox comboBox =(JComboBox)e.getSource();
           Object obj 
          =
           comboBox.getSelectedItem();
           TableModel jTable1Model 
          = null
          ;
            
          if(obj instanceof
           Person){
                jTable1Model 
          = new
           DefaultTableModel(
                                    
          new String[][] { { "Name"
          , ((Person)obj).getName() },
                                                     { 
          "Sex"
          , ((Person)obj).getSex() },
                                                      { 
          "Age"
          , ((Person)obj).getAge() }},
                                     
          new String[] { "Column 1""Column 2"
           });
            }
            
          if(obj instanceof
           Product){
                jTable1Model 
          = new
           DefaultTableModel(
                                  
          new String[][] { { "Name"
          , ((Product)obj).name },
                                                    { 
          "price"
          , ((Product)obj).price },
                                                    { 
          "quantity"
          , ((Product)obj).quantity }},
                                   
          new String[] { "Column 1""Column 2"
           });

            }
            table.setModel(jTable1Model);


          ClassDiagram3.JPG


          結(jié)果還是讓人滿意的:

          jframe1.JPG


          后來我感覺ActionListener代碼有一些凌亂,又封裝了一個Builder類,讓它創(chuàng)建TableModel:

          public static TableModel modelBuilder(Object obj){
          TableModel jTable1Model = null;
            
          if(obj instanceof
           Person){
                    jTable1Model 
          = new
           DefaultTableModel(
                       
          new String[][] { { "Name"
          , ((Person)obj).getName() },
                         { 
          "Sex"
          , ((Person)obj).getSex() },
                         { 
          "Age"
          , ((Person)obj).getAge() }},
                       
          new String[] { "Column 1""Column 2"
           });
                                    }
                                    
          if(obj instanceof
           Product){
                                      jTable1Model 
          = new
           DefaultTableModel(
                         
          new String[][] { { "Name"
          , ((Product)obj).name },
                           { 
          "price"
          , ((Product)obj).price },
                           { 
          "quantity"
          , ((Product)obj).quantity }},
                         
          new String[] { "Column 1""Column 2"
           });

            }
          return
           jTable1Model;

          }


          我對自己的代碼還算滿意,至少目前能用了。

          4.需求又變了

          第二天,組長告訴我,需求又變了,這會不但多增加一個“服裝”類型,Product類型屬性顯示有錯誤,并且需要增加一個Tree,顯示當前同種類型直接的層次結(jié)構(gòu),等等。

          我聽了領(lǐng)導嘮叨半個小時后,打開了我剛寫的Builder類,往里面增加著我的代碼……

          類圖大致如下:

          ClassDiagram4.JPG


          程序經(jīng)過修改后,好不容易又符合要求了,情況又發(fā)生了變化,組長需要我繼續(xù)修改。我無奈地看著組長,組長也無奈地看著我那用if-else堆成的代碼……

          “悲哀,真讓我替你感到悲~哀!”組長操著本山的腔調(diào)這樣對我說。

          是啊,多悲哀啊,一個設(shè)計上的錯誤讓我的代碼無法適應(yīng)需求的變化。

          好了,讓我們回到IAdaptable上。

          通過上面的例子,我看可以發(fā)現(xiàn)這么一個情況:同樣一個對象,在程序里面往往有許多不同的顯示方式(不僅僅是在UI顯示,在其他一些代碼里,需要轉(zhuǎn)化成另外類型或者數(shù)據(jù)結(jié)構(gòu))。

          如果我用IAdapteable的思想來實現(xiàn)剛才的Swing屬性顯示,會怎么樣呢?

          重新寫一遍ActionListener中的代碼:

          JComboBox comboBox =(JComboBox)e.getSource();
          Object obj 
          =
           comboBox.getSelectedItem();
          TableModel jTable1Model 
          = null
          ;
          if(obj instanceof
           IAdaptable){
                 jTable1Model 
          = (TableModel) ((IAdaptable)obj).getAdapter(TableModel.class
          );
          }
          table.setModel(jTable1Model);

          然后分別讓Person和Product實現(xiàn)IAdaptable接口:

          Class Person:
          public class Person implements
           IAdaptable{
             …..
             
          public
           Object getAdapter(Class clazz) {
            
          if(clazz == TableModel.class
          ){
              
          return new
           DefaultTableModel(
                
          new String[][] { { "Name"
          , getName() },
                  { 
          "Sex"
          , getSex() },
                  { 
          "Age"
          , getAge() }},
                
          new String[] { "Column 1""Column 2"
           });
            }
            
          return null
          ;
           }
          }

          Class Product
          public class Product implements
           IAdaptable{
           ……
              
          public
           Object getAdapter(Class clazz) {
            
          if(clazz == TableModel.class
          ){
              
          return new
           DefaultTableModel(
                
          new String[][] { { "Name"
          , getName() },
                  { 
          "Sex"
          , getSex() },
                  { 
          "Age"
          , getAge() }},
                
          new String[] { "Column 1""Column 2"
           });
            }
            
          return null
          ;
           }
          }

          其實我們的代碼量并沒有任何的改變,前后都是一樣的。

          但是我們將Table需要顯示的模型(TableModel),現(xiàn)在是作為擴展類接口抽取了出來,而那些需要在Table上顯示自己屬性的業(yè)務(wù)模型(Person,Product)實現(xiàn)了IAdaptable接口,將顯示模型(TableModel)作為了自己的擴展接口類型給予實例返回,并且UI代碼中,Table和業(yè)務(wù)模型之間形成一種契約:凡是實現(xiàn)了IAdaptable的接口才可以獲得在該Table上顯示的資格,并且Table從IAdaptable的getAdapter方法獲得顯示模型:

          ClassDiagram5.JPG



          這樣一來,我們的Swing程序不僅功能能夠?qū)崿F(xiàn),而且UI部分代碼和業(yè)務(wù)模型代碼之間的耦合性減小了。

          而且,如果需求發(fā)生變化,比如像剛才提到那樣“需要增加一個Tree,顯示當前同種類型直接的層次結(jié)構(gòu)”,那我們就在getAdaper方法中返回一個TreeModel的副本,然后在UI中增加一個Tree,讓它像Table一樣,從IAdaptable接口中取出我們的TreeModel即可——UI擴展也變得容易起來。

          現(xiàn)在我可以對組長說:讓需求變化來得更猛烈些吧!

          5.模型代碼無法修改

          有這樣一個問題:如果我們的模型已經(jīng)存在,而且代碼已經(jīng)無法修改了怎么辦?

          IAdapterFactory就是為這種情況準備的。

          先看看IAdapterFactory:

          public interface IAdaptableFactory {
           
          public
           Object getAdapter(Object adapter,Class clazz);
          }


          這里面的方法和IAdaptable差不多,只是多了一個參數(shù),這個參數(shù)就是需要我們返回Adapter接口的對象。

          在Eclipse中IAdapterFactory并不是單獨存在的,而是有一個IAdapterManager對它進行維護的:

          public interface IAdaptableManager {
           
          public
           Object getAdapter(Object adapter,Class clazz);
           
          public boolean
           registerAdapters (Class clazz,IAdaptableFactory factory);
          }


          現(xiàn)在讓我們這樣來修改剛才的Swing程序:

          假設(shè)Product類型是第三方提供的jar包,我們已經(jīng)無法修改它的代碼了,那我們就需要用到IAdapableFactory的擴展方法。請看下面的代碼

          Class AdaptableFactoryImpl
          public class AdaptableFactoryImpl implements
           IAdaptableFactory {
           
          public
           Object getAdapter(Object adapter, Class clazz) {
            
          if(adapter instanceof
           Product){
             
          if(clazz ==TableModel.class
          ){
              
          return new
           DefaultTableModel(
                
          new String[][] { { "Name"
          ,((Product)adapter).name },
                  { 
          "price"
          , ((Product)adapter).price },
                  { 
          "quantity"
          , ((Product)adapter).quantity }},
                
          new String[] { "Column 1""Column 2"
           });
             }
            }
            
          return null
          ;
           }
           
          public
           Class[] getAdapterList() {
            
          return new Class[]{TableModel.class
          };
           }
          }

          Class AdapterManagerImpl:
          public class AdapterManagerImpl implements
           IAdaptableManager {
           
          private static AdapterManagerImpl instance = null
          ;
           
          private Hashtable table = new
           Hashtable();
           
           
          private
           AdapterManagerImpl(){}
           
           
          public
           Object getAdapter(Object adapter, Class clazz) {
            Object factory 
          =
           table.get(adapter.getClass());
            
          if(factory != null
          ){
             
          return
           ((IAdaptableFactory)factory).getAdapter(adapter,clazz);
            }
            
          return null
          ;
           }

           
          public boolean
           registerFacotry(Class clazz, IAdaptableFactory factory) {
            
          try
          {
             table.put(clazz,factory);
             
          return true
          ;
            }
          catch
          (Exception e){
             
          return false
          ;
            }
           }
           
          public synchronized static
           AdapterManagerImpl getInstance() {
            
          if(instance == null) instance = new
           AdapterManagerImpl();
            
          return
           instance;
           }
          }


          有了這兩個實現(xiàn)類后,我們再去修改一下ActionListener中的代碼:

                   JComboBox comboBox = (JComboBox) e.getSource();
                   Object obj 
          =
           comboBox.getSelectedItem();
                   TableModel jTable1Model 
          = null
          ;
                   
          if (obj instanceof
           IAdaptable) {
                    jTable1Model 
          =
           (TableModel) ((IAdaptable) obj)
                      .getAdapter(TableModel.
          class
          );
                   } 
          else
           {
                    jTable1Model 
          =
           (TableModel) AdapterManagerImpl
                      .getInstance().getAdapter(obj,
                        TableModel.
          class
          );
                   }
                   table.setModel(jTable1Model);


          好了,只要我們在適當?shù)牡胤剑瑢AdaptableFactory注冊進IAdaptaerManager,那我們對無法修改代碼的業(yè)務(wù)模型也能進行接口的擴展了。

          6.結(jié)束語

          在Eclipse中,IAdaptable的應(yīng)用非常廣泛,而且如果實現(xiàn)了IAdaptable接口的類被成為Platform Object,可見IAdaptable在Eclipse框架中的分量。本人的知識有限,如果有遺漏或者錯誤的地方,還請各位讀者指出。

          classdiagram.JPG

          posted on 2006-01-10 16:56 小叉 閱讀(234) 評論(0)  編輯  收藏 所屬分類: 轉(zhuǎn)載
           
          Copyright © 小叉 Powered by: 博客園 模板提供:滬江博客
          主站蜘蛛池模板: 修文县| 西平县| 洪湖市| 沁阳市| 如皋市| 岳阳市| 裕民县| 阿坝| 武安市| 依兰县| 和林格尔县| 永定县| 开鲁县| 青海省| 丰原市| 金沙县| 南城县| 永定县| 柯坪县| 舒城县| 丹棱县| 安平县| 姜堰市| 平舆县| 开远市| 库车县| 偏关县| 吉首市| 岫岩| 榆树市| 怀远县| 都匀市| 白银市| 安平县| 松原市| 新平| 陆良县| 攀枝花市| 北流市| 濉溪县| 图木舒克市|