mercredi 26 octobre 2016

Extend/wrap an object ad-hoc with more functionality

The following question adresses a problem I often encounter. Basically, there are solutions like the adaptor pattern, but I find it a bit unsatisfying.

Suppose I have a class Polygon which implements an - uhm - polygon with quite some functionality. Many of those Polygon live in my program, some as lonely variables, some in collection structures.

Now, there's a function that needs an argument type that is basically a Polygon, but with some additional features. Let's say, a Polygon who can return some metrics: his volume, center of gravity, and angular mass. Plus, the function also needs the methods of the original Polygon.

A first idea is:

class Polygon:
# defines my polygon

class PolygonWithMetrics(Polygon):
# - extends polygon with the metrics
# - takes Polygon as argument upon construction
# - would need to delegate many functions to Polygon

def functionUsingPolygonWithMetrics(p):
# use functions of Polygon and PolygonWithMetrics

# driving code:
p = Polygon(some args here)
... more code ...
p_with_metrics = PolygonWithMetrics(p) # Bummer - problem here...
functionUsingPolygonWithMetrics(p_with_metrics)

The problem: It would require to delegate many many functions from PolygonWithMetrics into the original Polygon.

A second idea is:

class Polygon:
# defines my polygon

class PolygonMetrics:
# takes a polygon and provides metrics methods on it

def functionUsingPolygonWithMetrics(p):
# use functions of Polygon and PolygonMetrics

# driving code:
p = Polygon(some args here)
... more code ...
p_with_metrics = PolygonMetrics(p)
functionUsingPolygonWithMetrics(p, p_with_metrics) # Bummer - problem here...

This idea takes the original Polygon as an argument, plus a second object that provides the metrics functions. The problem is that I would need to change the signature of functionUsingPolygonWithMetrics.

What I would really need is an idea how to extend an existing object ad-hoc with some more functionality, without the problems given in idea 1 and 2.

I could imagine an idea roughly like this, where the job is mostly done by PolygonWithMetrics:

class Polygon:
# defines my polygon

class PolygonWithMetrics(maybe inherits something):
# - takes a Polygon and provides metrics methods on it
# - upon construction, it will take a polygon
# - will expose the full functionality of Polygon automatically

def functionUsingPolygonWithMetrics(p):
# use functions of Polygon and PolygonWithMetrics

# driving code:
p = Polygon(some args here)
... more code ...
p_with_metrics = PolygonWithMetrics(p)
functionUsingPolygonWithMetrics(p)

Three questions arise:

  • Does this pattern have sort of a name?
  • Is it a good idea, or should I resort to some more adviced techniques?
  • How to do it in Python?

Aucun commentaire:

Enregistrer un commentaire