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框架中的分量。本人的知识有限,如果有遗漏或者错误的地方,还请各位读者指出。

转:IAdaptable & IAdapterFactory的更多相关文章

  1. IAdaptable和IAdaptableFactory(转)

    先记在这里,回头研究下. 原文:http://blog.csdn.net/mini_snow/article/details/3877379 1. 简介和简单的实现 IAdapteable实际上在Ec ...

  2. GMF常见问题

    1.问题:连接线旁边没有文字标签和箭头 文字标签:在gmfmap里的Connection Mappping下增加Label Mapping元素:箭头:在gmfgraph里为Polyline Conne ...

  3. 关于Eclipse插件之IWorkbench IWorkbenchWindow IWorkbenchPage |WorkbenchPart......等的总结

    1..IWorkbench: workbench是eclipse用户界面中最底层的对象,它建立在Display之上,包含一个或多个IWorkbenchWindow,用于向终端用户呈现信息 当你的wor ...

  4. 关于Eclipse插件开发(四)-------给视图加下拉菜单和按钮和加入编辑器.

    本例将给视图加入下拉菜单和按钮,同时再为列表添加一个右键菜单. 创建ActionGroup类 加入菜单和按钮的方法与SWT和JFace组件的一样,先创建一个ActionGroup代码如下: MyAct ...

  5. Java 最常用类(前1000名) 来自GitHub 3000个项目

    这篇文章主要介绍了最常用的1000个Java类(附代码示例),需要的朋友可以参考下 分析Github 3000个开源项目,粗略统计如下.括号内的数字是使用频率 0-3000. 下面的列表显示不全,完整 ...

  6. Eclipse Common API

    Platform runtime Defines the extension point and plug-in model. It dynamically discovers plug-ins an ...

  7. Elipse plugin or Bundle & OSGI

    Develop and register service, lookup and use service! Android Design on service's publish-find-bind ...

  8. Eclipse Action

    Interface IAction package org.eclipse.jface.action; import org.eclipse.core.commands.IHandlerAttribu ...

  9. Eclipse插件开发中的选择监听机制(Selection Provider-Listener)

    Eclipse插件开发中的选择监听机制(Selection Provider-Listener) 监听机制是eclipse插件开发或rcp应用开发中经常使用的技术,比方点击TableViewer或Tr ...

随机推荐

  1. Go语言之并发编程(一)

    轻量级线程(goroutine) 在编写socket网络程序时,需要提前准备一个线程池为每一个socket的收发包分配一个线程.开发人员需要在线程数量和CPU数量间建立一个对应关系,以保证每个任务能及 ...

  2. hadoop完全分布式集群的搭建

    集群配置: jdk1.8.0_161 hadoop-2.6.1 linux系统环境:Centos6.5 创建普通用户  dummy 准备三台虚拟机master,slave01,slave02 hado ...

  3. 我给女朋友讲编程CSS系列(2)- CSS语法、3大选择器、选择器优先级

    首先看一下使用Css设置h1标签字体颜色和大小的例子,效果图如下: 新建一个网页test.html,然后复制粘贴下面的内容: <html> <head> <style t ...

  4. Hive jdbc连接出现java.sql.SQLException: enabling autocommit is not supported

    1.代码如下 String url = "jdbc:hive2://master135:10000/default"; String user = "root" ...

  5. Python+Selenium练习篇之18-获取元素上面的文字

    本文介绍如何通过Selenium方法来获取某一个元素的text属性值.在很多自动化测试脚本中,需要多次获取元素的text值,拿过来进行对比和匹配.例如,在一个登陆界面,如果不输入用户名和密码,直接点击 ...

  6. php获取当前操作系统类型

    如何使用 php 获取当前操作系统类型呢? 严格来说这里分两种情况,一种情况是获取 服务器端 的操作系统类型,一种是获取 客户端 的操作系统类型. 下面将对如何使用php获取这两种情况下的操作系统类型 ...

  7. LeetCode——Problem3:Longest Substring Without Repeating Characters

    哎哟我天啊.这道题快折磨死我了.刚开始连题都没看明白,就是不知道substring是什么意思.研究了好长时间才看出来的. 光辉历史呀...菜死了 1.题目 Given a string, find t ...

  8. c++中读取文件最快的方法

    https://www.byvoid.com/blog/fast-readfile 可以看看了.

  9. java流(二)

    目录 1 ObjectOutputStream/ObjectInputStream的使用 2 序列化 3 具体序列化的过程 4 Externalizable的简易介绍 实现序列化的Person类 /* ...

  10. ERROR org.apache.hadoop.hdfs.server.datanode.DataNode: Incompatible namespaceIDs

    用三台centos操作系统的机器搭建了一个hadoop的分布式集群.启动服务后失败,查看datanode的日志,提示错误:ERROR org.apache.hadoop.hdfs.server.dat ...