转: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中的值全部赋给它,并返回。
这样,我们就可以写出以下代码:
Vector v = (Vector) list.getAdapter(Vector. class );
ArrayList会返回Vector对象,这个对象是ArrayList的一个另外一种类型的副本。
2.一个Swing程序
读者会问:这有什么用啊,不就简单转化一下麽。其实说实话,从上面的代码来看确实没什么用,但是如果我们换一个场景试试。
写 这么一个Swing程序:有一个对话框,其中它有一个ComboBox和一个Table,ComboBox中存放的是一个名为Person类型的对象,当 ComboBox的选项发生改变的时候,就在Table上显示它的属性,我们假设这个Swing程序已经在某个项目中开始实施,并且其界面布局不易更改。
看看代码:
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中的部分代码:
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:
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中的代码:
Object obj = comboBox.getSelectedItem();
TableModel jTable1Model = null ;
if (obj instanceof IAdaptable){
jTable1Model = (TableModel) ((IAdaptable)obj).getAdapter(TableModel. class );
}
table.setModel(jTable1Model);
然后分别让Person和Product实现IAdaptable接口:
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 Object getAdapter(Object adapter,Class clazz);
}
这里面的方法和IAdaptable差不多,只是多了一个参数,这个参数就是需要我们返回Adapter接口的对象。
在Eclipse中IAdapterFactory并不是单独存在的,而是有一个IAdapterManager对它进行维护的:
public Object getAdapter(Object adapter,Class clazz);
public boolean registerAdapters (Class clazz,IAdaptableFactory factory);
}
现在让我们这样来修改刚才的Swing程序:
假设Product类型是第三方提供的jar包,我们已经无法修改它的代码了,那我们就需要用到IAdapableFactory的扩展方法。请看下面的代码
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中的代码:
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的更多相关文章
- IAdaptable和IAdaptableFactory(转)
先记在这里,回头研究下. 原文:http://blog.csdn.net/mini_snow/article/details/3877379 1. 简介和简单的实现 IAdapteable实际上在Ec ...
- GMF常见问题
1.问题:连接线旁边没有文字标签和箭头 文字标签:在gmfmap里的Connection Mappping下增加Label Mapping元素:箭头:在gmfgraph里为Polyline Conne ...
- 关于Eclipse插件之IWorkbench IWorkbenchWindow IWorkbenchPage |WorkbenchPart......等的总结
1..IWorkbench: workbench是eclipse用户界面中最底层的对象,它建立在Display之上,包含一个或多个IWorkbenchWindow,用于向终端用户呈现信息 当你的wor ...
- 关于Eclipse插件开发(四)-------给视图加下拉菜单和按钮和加入编辑器.
本例将给视图加入下拉菜单和按钮,同时再为列表添加一个右键菜单. 创建ActionGroup类 加入菜单和按钮的方法与SWT和JFace组件的一样,先创建一个ActionGroup代码如下: MyAct ...
- Java 最常用类(前1000名) 来自GitHub 3000个项目
这篇文章主要介绍了最常用的1000个Java类(附代码示例),需要的朋友可以参考下 分析Github 3000个开源项目,粗略统计如下.括号内的数字是使用频率 0-3000. 下面的列表显示不全,完整 ...
- Eclipse Common API
Platform runtime Defines the extension point and plug-in model. It dynamically discovers plug-ins an ...
- Elipse plugin or Bundle & OSGI
Develop and register service, lookup and use service! Android Design on service's publish-find-bind ...
- Eclipse Action
Interface IAction package org.eclipse.jface.action; import org.eclipse.core.commands.IHandlerAttribu ...
- Eclipse插件开发中的选择监听机制(Selection Provider-Listener)
Eclipse插件开发中的选择监听机制(Selection Provider-Listener) 监听机制是eclipse插件开发或rcp应用开发中经常使用的技术,比方点击TableViewer或Tr ...
随机推荐
- 快速获取Android应用包名和Activity名
一.获取包名 方法1: 先说明一下这里讲的方法是通用的,而网上其他方法获取PackageName不通用(因为他是建立在root的基础上的,我不敢保证你的设备已经root). ①在android设备上点 ...
- 数据库——初始mysql语句(2)
sql语句 #1. 操作文件夹(库) 增:create database db1 charset utf8; 查:show create database db1; show databases; 改 ...
- 贪吃蛇—C—基于easyx图形库(上):基本控制函数实现 画图程序
自从学了c语言,就一直想做个游戏,今天将之付之行动,第一次写的特别烂,各种bug:就不贴了.今天网上看了好几个贪吃蛇,重新写了一次,做出来的效果还可以. p.s. easyx图形库是为了方便图形学教 ...
- 【转】Using Raycasts and Dynamically Generated Geometry to Create a Line of Sight on Unity3D
http://www.linkedin.com/pulse/using-raycasts-dynamically-generated-geometry-create-line-thomas José ...
- BZOJ 1864:[Zjoi2006]三色二叉树(树DP)
三色二叉树 问题描述 输入 仅有一行,不超过500000个字符,表示一个二叉树序列. 输出 输出文件也只有一行,包含两个数,依次表示最多和最少有多少个点能够被染成绿色. 样例输入 1122002010 ...
- 【bzoj1367】[Baltic2004]sequence 可并堆
题目描述 输入 输出 一个整数R 样例输入 7 9 4 8 20 14 15 18 样例输出 13 题解 可并堆,黄源河<左偏树的特点及其应用>Page 13例题原题 #include & ...
- 一个 Observation
$n$ 个小球分布在一个圆上,小球的颜色或黑或白.顺时针(或逆时针)遍历这 $n$ 个小球,记录下相邻两小球的颜色,得到 $n$ 个有序颜色对.我们有,(黑,白)和(白,黑)的数目一定相等(可能都是 ...
- Hibernate逆向工程生成代码
编辑此文章,其目的是方便以后根据表生成相应的代码,然而并非所有的代码都是如此.这里的Hibernate 即响应题目的ssh框架中的“h”. 如图所示,点击右上角,在myeclipse之中.再点击Mye ...
- 【12】react 之 redux(1)
TodoList小demo 效果展示 项目地址 (单向)数据流 数据流是我们的行为与响应的抽象:使用数据流能帮我们明确了行为对应的响应,这和react的状态可预测的思想是不谋而合的. 常见的数据流框架 ...
- Master of Sequence
Master of Sequence 时间限制: 10 Sec 内存限制: 128 MB 题目描述 There are two sequences a1,a2,...,an , b1,b2,..., ...