Decorator Design Techniques
We can use the integer conversion as follows:
drop_punct("1,701")
1701
drop_punct("97")
97
While this can encapsulate some sophisticated cleansing and converting into a
very tidy package, the results are potentially confusing. The name of the function
is the name of the core cleansing algorithm; the other function's contribution to the
composite is lost.
As an alternative, we can use the integer conversion as follows:
def drop_punct(text):
return text.replace(",", "").replace("$", "")
drop_punct_int = then_convert(int)(drop_punct)
This will allow us to provide a new name to the decorated cleaning function.
This solves the naming problem, but the construction of the final function via the
then_convert(int)(drop_punct) method is rather opaque.
It seems like we've reached the edge of the envelope here. The decorator model
isn't ideal for this kind of design. Generally, decorators work well when we have a
number of relatively simple and fixed aspects that we want to include with a given
function (or a class). Decorators are also important when these additional aspects
can be looked at as an infrastructure or a support, and not something essential to the
meaning of the application code.
For something that involves multiple orthogonal dimensions, we might want to
result to the Callables function with various kinds of plugin strategy objects.
This might provide something more palatable. We might want to look closely at
creating higher-order functions. We can then create partial functions with various
combinations of parameters for the higher-order functions.
The typical examples of logging or security testing can be considered as the kind
of background processing that isn't specific to the problem domain. When we have
processing that is as ubiquitous as the air that surrounds us, then a decorator might
be more appropriate.