<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    月蝕傳說

    浮躁讓人失去理智
    posts - 25, comments - 101, trackbacks - 0, articles - 0
      BlogJava :: 首頁 ::  :: 聯(lián)系 :: 聚合  :: 管理

    IAdaptable和IAdaptableFactory

    Posted on 2006-10-09 19:08 Dart 閱讀(1816) 評論(3)  編輯  收藏 所屬分類: Eclipse

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

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

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

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

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


    ArrayList會(huì)返回Vector對象,這個(gè)對象是ArrayList的一個(gè)另外一種類型的副本。

    2.一個(gè)Swing程序

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

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

    看看代碼:

    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(
    218 ,? 2 ,? 171 ,? 248
    );
    ??????}
    ??????{
    ???????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);
    ??????????????????????}
    ??????????????????});

    ??????}




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


    3.需求變更

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

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

    無奈,我新增加了一個(gè)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);



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


    后來我感覺ActionListener代碼有一些凌亂,又封裝了一個(gè)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.需求又變了

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

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

    類圖大致如下:




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

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

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



    好了,讓我們回到IAdaptable上。

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

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

    重新寫一遍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實(shí)現(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
    ;
    ?}
    }

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

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



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

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

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


    5.模型代碼無法修改

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

    IAdapterFactory就是為這種情況準(zhǔn)備的。

    先看看IAdapterFactory:

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


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

    在Eclipse中IAdapterFactory并不是單獨(dú)存在的,而是有一個(gè)IAdapterManager對它進(jìn)行維護(hù)的:

    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的擴(kuò)展方法。請看下面的代碼

    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;
    ?}
    }


    有了這兩個(gè)實(shí)現(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);


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

    6.結(jié)束語

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


    評論

    # re: IAdaptable和IAdaptableFactory  回復(fù)  更多評論   

    2007-03-27 16:53 by iceman
    寫得清楚,謝謝

    # re: IAdaptable和IAdaptableFactory  回復(fù)  更多評論   

    2007-05-17 11:40 by re
    看不到圖片了

    # re: IAdaptable和IAdaptableFactory  回復(fù)  更多評論   

    2011-03-03 08:48 by d
    寫得很好的。
    主站蜘蛛池模板: 久久久国产精品无码免费专区| 中文国产成人精品久久亚洲精品AⅤ无码精品| 一级毛片视频免费| wwwxxx亚洲| 亚洲人成在线观看| 亚洲中文字幕无码久久精品1 | 亚洲AV无码不卡在线观看下载 | 亚洲视频日韩视频| 在线观看国产区亚洲一区成人| 成人免费无码大片A毛片抽搐| 最好看的中文字幕2019免费| 99久久免费国产精品热| 一级全免费视频播放| 国产亚洲福利精品一区二区| 亚洲精品综合在线影院| 亚洲欧洲综合在线| 在线电影你懂的亚洲| 亚洲成av人片在线观看无码不卡| 国产亚洲色婷婷久久99精品91| 无码欧精品亚洲日韩一区夜夜嗨 | 桃子视频在线观看高清免费完整| 日韩精品在线免费观看| 成人免费av一区二区三区| 国产成人综合亚洲| 精品国产亚洲第一区二区三区| 亚洲欧美日韩国产精品一区| 亚洲日本在线电影| 亚洲第一成年网站视频| 亚洲国产成人久久精品大牛影视 | 99久久久国产精品免费无卡顿| 99在线观看免费视频| 久久国产乱子伦精品免费看| 国产好大好硬好爽免费不卡 | 亚洲色av性色在线观无码| 亚洲精品人成在线观看| 亚洲视频在线观看免费| 精品亚洲成a人片在线观看| 亚洲欧洲日产国码www| 亚洲婷婷在线视频| 久久夜色精品国产噜噜亚洲a| 亚洲AV无码一区二区三区电影|