• 转:IAdaptable & IAdapterFactory


    IAdaptable & IAdapterFactory在Eclipse中使用IAdaptable接口的方式有两种

     

    在Eclipse中使用IAdaptable接口的方式有两种
    1:某个类希望提供新的接口,但又不希望将其暴露在API中,在这种情况下,IAdaptable接口中的方法getAdaptor()方法将由本类实现。(希望支持新的接口,而又不想把已经发布的API造成影响,这种机制很有用)
    2:外界要求某个类提供新的服务,这种情况下不需要修改现有类的代码,getAdaptor()由一个工厂提供。(不使用decorator模式的原因是在以后的对比中会出现两个含有相同接口的类)
    创建适配器工厂(IAdapterFactory),注册到适配器管理器(IAdapterManager),
    代码如下:IadapterFactory factory = new AdapterFactory();
    IadapterManager manager = Platform.getAdapterManager();
    Manager.registerAdapters(factory,Ifile.class);

    适配对象需要实现platformobject
    public Object getAdapter(Class adapter)
    {
               return InternalPlatform.getDefault().getAdapterManager().getAdapter(this, adapter);
         }
    若未实现,则需要下列调用:Platform.getAdapterManager().getAdapter(this,adapter)



    (Quote from http://www.blogjava.net/reloadcn/archive/2006/10/09/74153.aspx)

    1. 简介和简单的实现 

    IAdapteable实际上在Eclipse早期版本中不叫这个名字,它原来的名字叫做IExtensible,顾名思义就是可以扩展的意思,后来为了更能突出是由一个类配适到一个接口这么一种机制,所以改名为IAdaptable。
    这个接口有什么用呢,其实说白了,就是提供一个类型的转换机制。比如下面这段代码:

     

    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,并且实现了IAdaptable接口,我们想要将它转化成Vector类型对象,于是在getAdapter方法中我们判断 传入参数类型,如果是Vector类那么就新生成一个Vector对象,将ArrayList中的值全部赋给它,并返回。

    这样,我们就可以写出以下代码:

     

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

     


    ArrayList会返回Vector对象,这个对象是ArrayList的一个另外一种类型的副本。 

    2.一个Swing程序 

    读者会问:这有什么用啊,不就简单转化一下麽。其实说实话,从上面的代码来看确实没什么用,但是如果我们换一个场景试试。

    写 这么一个Swing程序:有一个对话框,其中它有一个ComboBox和一个Table,ComboBox中存放的是一个名为Person类型的对象,当 ComboBox的选项发生改变的时候,就在Table上显示它的属性,我们假设这个Swing程序已经在某个项目中开始实施,并且其界面布局不易更改。

     

    看看代码:

     

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

          }


     

     



     运行我们的代码,会发现效果还可以,每当我们选项改变的时候,Table就如同一个属性栏一样,改变着自己的内容:

     

     

     

     

     


    3.需求变更 

    OK,问题来了。我写完这段代码后,组长告诉我,现在我们有一个新的需求,就是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);


     

     


    结果还是让人满意的:

     

     

     

     

    后来我感觉ActionListener代码有一些凌乱,又封装了一个Builder类,让它创建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,显示当前同种类型直接的层次结构,等等。

    我听了领导唠叨半个小时后,打开了我刚写的Builder类,往里面增加着我的代码……

    类图大致如下:


      

    程序经过修改后,好不容易又符合要求了,情况又发生了变化,组长需要我继续修改。我无奈地看着组长,组长也无奈地看着我那用if-else堆成的代码……

    “悲哀,真让我替你感到悲~哀!”组长操着本山的腔调这样对我说。

    是啊,多悲哀啊,一个设计上的错误让我的代码无法适应需求的变化。

     

     

     



    好了,让我们回到IAdaptable上。

    通过上面的例子,我看可以发现这么一个情况:同样一个对象,在程序里面往往有许多不同的显示方式(不仅仅是在UI显示,在其他一些代码里,需要转化成另外类型或者数据结构)。

    如果我用IAdapteable的思想来实现刚才的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实现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),现在是作为扩展类接口抽取了出来,而那些需要在Table上显示自己属性的业务模型 (Person,Product)实现了IAdaptable接口,将显示模型(TableModel)作为了自己的扩展接口类型给予实例返回,并且UI 代码中,Table和业务模型之间形成一种契约:凡是实现了IAdaptable的接口才可以获得在该Table上显示的资格,并且Table从 IAdaptable的getAdapter方法获得显示模型:

     

     

     



    这样一来,我们的Swing程序不仅功能能够实现,而且UI部分代码和业务模型代码之间的耦合性减小了。

    而 且,如果需求发生变化,比如像刚才提到那样“需要增加一个Tree,显示当前同种类型直接的层次结构”,那我们就在getAdaper方法中返回一个 TreeModel的副本,然后在UI中增加一个Tree,让它像Table一样,从IAdaptable接口中取出我们的TreeModel即可—— UI扩展也变得容易起来。

    现在我可以对组长说:让需求变化来得更猛烈些吧!

     

     

     


    5.模型代码无法修改 

    有这样一个问题:如果我们的模型已经存在,而且代码已经无法修改了怎么办?

    IAdapterFactory就是为这种情况准备的。

    先看看IAdapterFactory:

     

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

     


    这里面的方法和IAdaptable差不多,只是多了一个参数,这个参数就是需要我们返回Adapter接口的对象。

    在Eclipse中IAdapterFactory并不是单独存在的,而是有一个IAdapterManager对它进行维护的:

     

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

     


    现在让我们这样来修改刚才的Swing程序:

    假设Product类型是第三方提供的jar包,我们已经无法修改它的代码了,那我们就需要用到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;
     }
    }

     


    有了这两个实现类后,我们再去修改一下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);

     


    好了,只要我们在适当的地方,将IAdaptableFactory注册进IAdaptaerManager,那我们对无法修改代码的业务模型也能进行接口的扩展了。

    6.结束语

    在Eclipse中,IAdaptable的应用非常广泛,而且如果实现了IAdaptable接口的类被成为Platform Object,可见IAdaptable在Eclipse框架中的分量。本人的知识有限,如果有遗漏或者错误的地方,还请各位读者指出。

     

     

     

  • 相关阅读:
    数组顺序表
    指针、数组、结构体
    急救模式下安装rpm包
    如何杀死远程服务器到本机的tcp连接
    centos升级内核之后修改内核启动顺序
    rpm yum 等命令无响应的解决方法
    关于ssh 设置的相关总结(ssh最大连接数、ssh连接时长、安全性配置等)
    详解Linux中的日志及用日志来排查错误的方法
    linux 普通用户登陆系统su
    如何更新/升级Red Hat Enterprise Linux内核?
  • 原文地址:https://www.cnblogs.com/kira2will/p/6282866.html
Copyright © 2020-2023  润新知