Home | Trees | Index | Help |
|
---|
Package Modeling :: Module delegation |
|
delegation module.
Suppose you are about to develop a reusable component offering a secure login service. This component might need two different sorts of features: say, a mandatory procedure to check login and password, and some optional others, e.g. a special procedure to be called when the maximal number of login attempts is reached. Your component implements a default procedure to check credentials against, say, the /etc/password file, and does not have any limit on the number of retries after failure.
However and since this is a reusable component you wish that the procedure that checks credentials, the maximum number of failures and the action to be taken can be conveniently changed at runtime.
One approach consists in making these parameters settable in your component ; this will work well, but this may not be really convenient:
The delegation offers you a general mechanism to solve these two issues. The DelegateWrapper class allows the following features:
[1] | of course, you may run into cases where such a design is inaccurate. All this is obviously a general discussion which might be inadequate given a specific architecture or design philosophy! |
[2] | except if you enforce your own rules, such as "if the delegates provides methodOne it should provide methodTwo as well", but this an other story (see DelegateWrapper.respondsTo()) |
We will stick on the example exposed above to explain how delegation is achieved with this module.
First, define a general "interface": a class, which defines and documents the methods a delegate for your component might implement:
The delegation
module supplies one class, DelegateWrapper
, to handle
delegate. Its role is to inspect a delegate's interface...
To use it, your reusable component's class will look like:
The delegate itself, as it will be provided by the users of the reusable
component, can be an instance of any class. You should have noticed in the
sample code above that the DelegateWrapper
acts as a proxy : it
automatically forwards any function call it cannot service (see Gotchas,
below) to the wrapped object --the real delegate). Note, however, that the
DelegateWrapper
is not an "absolute" proxy: the forwarded messages
are __only__ those which are declared in the delegate's interface.
There are several points which you should be aware of when using this class, some of which should be indicated in your own documentation:
the DelegateWrapper works by inspecting the interface-class and registering the signatures of its methods. By signature we mean: name, parameters and their default values, if any. These signatures are then compared to those of the delegate object when it is supplied. Thus:
if a delegate object does implement a function whose name matches one of the delegate's API but which uses different number of parameters, the same number of parameter with different names, or the same number of parameters and the same names but with different default values, this function will not be considered as an valid delegate method (hence 'respondsTo(thatMethodName)' will be false).
The DelegateWrapper determines the mapping between the delegate's API and the delegate object when this object is supplied ('setDelegateObject()') ; this mapping determines the answer for message 'respondsTo' as well as whether that message should be forwarded to the delegate by the DelegateWrapper.
Thus, if the delegate object can change at runtime, e.g. not responding to a message at some point of runtime and being able to service the same message later, that message will never be considered available. In that case, the provider for the delegate object should take care to call the component's 'setDelegate()' method each time the delegate object changes --this ensures that the mapping between the delegate's API and the object's capabilities is correctly recomputed.
The DelegateWrapper
itself declares some methods:
DelegateWrapper.respondsTo
, DelegateWrapper.delegateObject
,
DelegateWrapper.setDelegateObject
,
DelegateWrapper.reevaluateDelegateObject
. If the delegate's interface uses
at least one of these methods, the automatic forwarding of method calls is
automatically disabled. In that case, a warnings is issued (warning level:
RuntimeWarning) when the delegate object is set. You can still send
messages to the delegate object by sending the messages to the
DelegateWrapper.delegateObject()
.
Copyright (c) 2001-2004, Sebastien Bigaret All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the software's copyright holder, Sebastien Bigaret, nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
$Id: delegation.py,v 1.5 2004/08/02 20:54:47 sbigaret Exp $
Classes | |
---|---|
DelegateWrapper |
The DelegateWrapper: |
Home | Trees | Index | Help |
|
---|
Generated by Epydoc 2.1 on Sat Mar 4 13:36:24 2006 | http://epydoc.sf.net |