-
Add a service interface to a type without exposing it in that type
-
Add behavior to preexisting types such as IFile
The pattern is called Extension Object and is also known as Extension Interface. Anticipate that an object's interface needs to be extended in the future. Extension Object lets you add interfaces to a class and lets clients query whether an object has a particular extension。
The Eclipse extension support is class-based. That is, you can add behavior to existing classes, but not add state to its existing instances. The additional behavior is described by an interface.
getAdapter() returns an object castable to the given class (or null if the interface isn't supported)。
The IAdaptable interface is used in two different ways in Eclipse:
1)A class wants to provide additional interfaces without exposing them in the API— In this case, getAdapter() is implemented by the class itself. Adding a new interface requires changing the implementation of getAdapter(). This is useful when a class wants to support additional interfaces without changing its existing interface and thereby breaking the API.Here is an implementation of a getAdapter() method in a class that supports the IPropertySource interface:
Object getAdapter(Class adapter) {
if (adapter.equals(IPropertySource.class)
return new PropertySourceAdapter(this);
return super.getAdapter(adapter);
}
public class PropertySourceAdapter implements IPropertySource {
2)A class is augmented from the outside to provide additional services— In this case, no code changes to the existing class are required and the getAdapter() implementation is contributed by a factory. AdapterFactories—Adding Interfaces to Existing Types。
private Object source;
public PropertySourceAdapter(Object source) {
this.source= source;
}
public IPropertyDescriptor[] getPropertyDescriptors() {
// return the property descriptors.
}
//...
}
public class FileWithProperties implements IPropertySource {
private IFile file;
public IPropertyDescriptor[] getPropertyDescriptors() {...}
public Object getPropertyValue(Object id) {...}
public boolean isPropertySet(Object id) {...}
public void resetPropertyValue(Object id) {...}
public void setPropertyValue(Object id, Object value) {...}
public IFile toFile() { return file; }
}
class FileAdapterFactory implements IAdapterFactory {
// The purpose of this declarative method is to enable a quick lookup for an adapter.
public Class[] getAdapterList() {
return new Class[] {
IPropertySource.class
};
}
public Object getAdapter(Object o, Class adapter) {
if (adapter == IPropertySource.class)
return new FilePropertySource((IFile)o);
return null;
}
}
Next we have to register the factory for our desired type (IFile) with the AdapterManager.
IAdapterManager manager = Platform.getAdapterManager();
IAdapterFactory factory = new FileAdapterFactory();
manager.registerAdapters(factory, IFile.class);
Geting adapter interface by calling:
Platform.getAdapterManager().getAdapter(this, adapter);
Here are some points about the extension mechanism:
1) Multiple adapters for the same type— What happens when the same adapter is registered more than once in a type's hierarchy? The rule is that the most specific adapter wins. Most specific means the first adapter in the base class chain followed by a depth-first order search in the interface hierarchy.
2) Stateless adapters— Adapters that have no state are the most space-efficient and easiest to manage. You store a single instance of the adapter in a field of the adapter factory or a static variable and return it when it is requested. To reuse a single instance of the adapter for all adapted objects, the adapter methods need to support passing in the adapted object. IWorkbenchAdapter is an interface that enables a stateless implementation. IPropertySource is an interface that does not.
3) Instance based extensions— IAdaptable supports class extensions. How can you extend instances? IResource supports dynamic-state extension with properties. A property is identified by a qualified name and can be managed either per session or persistently. Refer to the API specification of IResource for more details.
Which adapters are supported?— You cannot determine the available adapters from just looking at a class interface. You have to read the API documentation to find out which adapters are expected by a service (see for example, org.eclipse.ui.views.properties.PropertySheet). Alternatively, search for references to IAdaptable.getAdapter() to uncover all uses of adapter interfaces.
4) Adapter negotiation— An IAdaptable client can ask for different interfaces until a suitable one is found. For example, a property sheet can be populated from an IPropertySource adapter. However, a client can also get full control over the Property Sheet view contents by providing an IPropertySheetPage adapter. The Property Sheet view first queries for an IPropertySheetPage adapter and if there isn't one then it uses a default Property Sheet page that queries for the IPropertySource adapter.
5) Reduced programming comfort— Programming with adapters is more bulky than programming with interfaces directly. With an adapter a direct method call is replaced by multiple statements:
IPropertySource source=
(IPropertySource) object.getAdapter(IPropertySource.class);
if (source != null)
return source.getPropertyDescriptors();
Extension Object—implemented as IAdaptable, IAdapterManager, and IAdapterFactory—furthers Eclipse's goal of supporting unanticipated extension by allowing contributors to extend the classes an object can pretend to be. While more complicated than just using objects, the extra complexity is balanced by the additional flexibility.
Extension Object Pattern
最新推荐文章于 2024-09-30 11:27:43 发布
We need a mechanism that allows us to