
git-svn-id: svn://svn.cy55.de/Zope3/src/cybertools/trunk@2465 fd906abe-77d9-0310-91a1-e0d9ade77398
125 lines
3.4 KiB
Text
125 lines
3.4 KiB
Text
==========================
|
|
A Simple Adapter Framework
|
|
==========================
|
|
|
|
$Id$
|
|
|
|
To work with adapters we need at least two classes, one for objects
|
|
that we want to adapt to (the adapter's `context`) and one for the adapters.
|
|
|
|
|
|
Adapter Classes and Factories
|
|
=============================
|
|
|
|
>>> class Content(object):
|
|
... pass
|
|
|
|
>>> class StateAdapter(object):
|
|
... def __init__(self, context):
|
|
... self.context = context
|
|
... def setState(self, state):
|
|
... self.context._state = state
|
|
... def getState(self):
|
|
... return getattr(self.context, '_state', 'initial')
|
|
|
|
In order to use the adapters in a flexible way we create adapter objects
|
|
by using an adapter factory. The stateful factory is intended to create
|
|
adapters that allow setting and retrieving the state of objects.
|
|
|
|
>>> from cybertools.util.adapter import AdapterFactory
|
|
>>> stateful = AdapterFactory()
|
|
|
|
We can now register our StateAdapter class with the `stateful` AdapterFactory.
|
|
We have to tell the factory which class of adapted objects a certain
|
|
adapter class is responsible for.
|
|
|
|
>>> stateful.register(StateAdapter, Content)
|
|
|
|
Now we are ready to create an object of the Content class
|
|
|
|
>>> c1 = Content()
|
|
|
|
and a corresponding `stateful` adapter:
|
|
|
|
>>> c1State = stateful(c1)
|
|
|
|
The adapter can now be used to access the Content object's state:
|
|
|
|
>>> c1State.getState()
|
|
'initial'
|
|
>>> c1State.setState('visible')
|
|
>>> c1State.getState()
|
|
'visible'
|
|
|
|
The procedure also works with subclasses of the Content class.
|
|
|
|
>>> class SpecialContent(Content):
|
|
... pass
|
|
|
|
>>> sc1 = SpecialContent()
|
|
>>> sc1State = stateful(sc1)
|
|
>>> sc1State.getState()
|
|
'initial'
|
|
>>> sc1State.setState('public')
|
|
>>> sc1State.getState()
|
|
'public'
|
|
|
|
But if we try to use an adapter factory for objects for which there is
|
|
no adapter registered we get back None.
|
|
|
|
>>> class UnknownContent(object):
|
|
... pass
|
|
|
|
>>> uc1 = UnknownContent()
|
|
>>> uc1State = stateful(uc1)
|
|
>>> uc1State is None
|
|
True
|
|
|
|
Class adapters as factories
|
|
---------------------------
|
|
|
|
There is a special case that can be handled with an adapter factory:
|
|
creating objects via an adapter to a class. An example for this is
|
|
a class that creates objects by loading them from a file or database,
|
|
so this would be a storage adapter class.
|
|
|
|
In our example we avoid reading from disk or from a database but just
|
|
create the object wanted by using the context's constructor.
|
|
|
|
>>> class ContentLoader(object):
|
|
... def __init__(self, context):
|
|
... self.context = context
|
|
... def load(self):
|
|
... return Content()
|
|
|
|
>>> storage = AdapterFactory()
|
|
>>> storage.register(ContentLoader, Content)
|
|
|
|
In this case we get the adapter from the adapter factory by providing
|
|
it with the context class (instead of an instance of it like in the
|
|
example above.
|
|
|
|
>>> loader = storage(Content)
|
|
>>> c2 = loader.load()
|
|
>>> c2
|
|
<Content object ...>
|
|
|
|
|
|
Self-registering Adapters
|
|
=========================
|
|
|
|
>>> from cybertools.util.adapter import adapters, AdapterBase
|
|
>>> stateful = AdapterFactory()
|
|
|
|
>>> class StateAdapter(AdapterBase):
|
|
... __adapterinfo__ = stateful, Content
|
|
... def __init__(self, context):
|
|
... self.context = context
|
|
... def setState(self, state):
|
|
... self.context._state = state
|
|
... def getState(self):
|
|
... return getattr(self.context, '_state', 'initial')
|
|
|
|
>>> stateful._registry
|
|
{(<class 'Content'>, ''): <class 'StateAdapter'>}
|
|
|