本站首页    管理页面    写新日志    退出


«September 2023»
12
3456789
10111213141516
17181920212223
24252627282930


公告

关注电子政务、大型企业应用开发、Web、Workflow、MOM、MDA、RCP、GEF

email:gmluyang@gmail.com


链接

好友
bluedavy-林昊
刑红瑞
SixSun-翻译
Birt中文指南
SixSun-OpenDoc
Eclipse RCP and Web in action(编写中)

我的分类(专题)

日志更新

最新评论

留言板


Blog信息
blog名称:SixSun的Blog
日志总数:152
评论数量:372
留言数量:13
访问次数:2366596
建立时间:2004年12月13日




[Rich Client Platform]IAdaptable和IAdaptableFactory(ZT)
文章收藏,  软件技术

SixSun 发表于 2007/2/5 17:01:54

原文:http://www.blogjava.net/reloadcn/archive/2006/10/09/74153.aspx 对Eclipse中IAdaptable和IAdaptableFactory 模式解释的非常清晰,解决问题的方式也很符合平时的开发习惯,作者功力了得。 IAdaptableFactory 实际开发的时候可以通过手工注册或扩展点的方式进行注册。在Contributing to Eclipse中文版 一书中也有解释,但我认为这个是最好的一个。 1. 简介和简单的实现 IAdapteable实际上在Eclipse早期版本中不叫这个名字,它原来的名字叫做IExtensible,顾名思义就是可以扩展的意思,后来为了更能突出是由一个类配适到一个接口这么一种机制,所以改名为IAdaptable。这个接口有什么用呢,其实说白了,就是提供一个类型的转换机制。比如下面这段代码: Class IAdaptable  public   interface  IAdaptable  {  public  Object getAdapter(Class clazz);}Class ListAdapterpublic   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 personpublic   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);                      }                  });      } 500)this.width=500'>  运行我们的代码,会发现效果还可以,每当我们选项改变的时候,Table就如同一个属性栏一样,改变着自己的内容: 500)this.width=500'> 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); 500)this.width=500'> 结果还是让人满意的: 500)this.width=500'> 后来我感觉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类,往里面增加着我的代码……类图大致如下:500)this.width=500'> 程序经过修改后,好不容易又符合要求了,情况又发生了变化,组长需要我继续修改。我无奈地看着组长,组长也无奈地看着我那用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 Productpublic   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方法获得显示模型: 500)this.width=500'> 这样一来,我们的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 AdaptableFactoryImplpublic   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); 好了,只要我们在适当


阅读全文(11234) | 回复(2) | 编辑 | 精华
 


回复:IAdaptable和IAdaptableFactory(ZT)
文章收藏,  软件技术

f(游客)发表评论于2009/6/16 15:11:43

fds


个人主页 | 引用回复 | 主人回复 | 返回 | 编辑 | 删除
 


回复:IAdaptable和IAdaptableFactory(ZT)
文章收藏,  软件技术

11111(游客)发表评论于2007/2/6 16:46:37

很好,很强大

个人主页 | 引用回复 | 主人回复 | 返回 | 编辑 | 删除
 


» 1 »

发表评论:
昵称:
密码:
主页:
标题:
验证码:  (不区分大小写,请仔细填写,输错需重写评论内容!)



站点首页 | 联系我们 | 博客注册 | 博客登陆

Sponsored By W3CHINA
W3CHINA Blog 0.8 Processed in 0.035 second(s), page refreshed 144752194 times.
《全国人大常委会关于维护互联网安全的决定》  《计算机信息网络国际联网安全保护管理办法》
苏ICP备05006046号