[Edu-sig] Design Patterns

Kirby Urner urnerk at qwest.net
Sat Aug 27 17:19:17 CEST 2005


> Separating these matters in an educational setting is more than
> problematic.
> 
> Art

In an educational setting, I use analogies.  

Think of interacting with a waiter in a restaurant.  Your expectation is you
name the foods and drinks you want, and after a period of time, those items
arrive at your table.  Later still, you pay for it all plus leave a tip.
That's the API.  

But in some restaurants, the waiter is proud to memorize your order, and
writes nothing.  In some, the order is written down, but punched into a
computer and the bill comes as a machine-printed slip.  

In most restaurants, the food is prepared in a kitchen not visible to
customers.  In others, it's prepared right in front of you, behind a
counter, while you watch.

Customers come to restaurants fully expecting to use the waiter API.  But
they may have little insight into the nuts and bolts of how this API is
wired up behind the scenes.

Maybe the waiter is part time.  Maybe the cook lives in Hoboken.  These
details, though real, are "hidden" from the customers (but may come out in
conversation).  Furthermore, the inner workings may change.  A new
computerized checkout device is installed.  Waiters need to be retrained,
but not customers.  The API is the same.

In my MVC example, the Viewer expected a 'shape' object to support a
specific API:  verts and edges needed to be available as attributes.  

class Vpyview(object):
    """
    A viewer: view using VPython
    """

    def display(self, shape):
        self._garbagecollect()
        self._showverts(shape.verts)
        self._showedges(shape.edges, shape.verts)
        time.sleep(.1)

But my Model class (a Triangle) defined neither per se.  The information was
there, but the API was not in accordance with the Viewer's needs.  

Presumably this Viewer is used with other shapes (polyhedra even!) and we
don't want to write exceptional code just around triangles -- that'd get
messy in a hurry.  

My solution, in this case, was to subclass Triangle2 and supply the missing
attributes in the subclass.  

In the case of edges, this was a static list, defined once and for all in
the constructor.  

In the case of verts, I used a property, so that the Viewer could just ask
for verts (not a callable) and so that a triangle could quickly figure
coords (also a property) behind the scenes. 

The upshot:  shape.verts, in the eyes of the viewer, is simply a dictionary
of xyz tuples with vertex label keys.

class Triangle2(BaseTriangle):
    """
    Model
    """

    ...

    @property
    def coords(self):
        return {'A':self._pA, 'B':self._pB, 'C':self._pC}

    def _reset(self):
        ...
        self._pA = (0.0, 0.0, 0.0)
        self._pB = (a  , 0.0, 0.0)
        self._pC = ((a**2 + b**2 - c**2)/(2.0*a),
                     math.sqrt((-a+b+c)*(a-b+c)*(a+b-c)*(a+b+c))/(2*a),
                     0.0)         

class TriAdapter(Triangle2):
    """
    Make a triangle work like a Shape, i.e. add
    edges and verts attributes
    """

    def __init__(self, a,b,c):
        Triangle2.__init__(self, a,b,c)
        self.edges = [('A','B'),('B','C'),('C','A')]
        
    @property
    def verts(self):
        return self.coords

Why allow coords and verts to be properties?  Because these triangles are
themselves mutable and the vertices may change position, even if how they're
connected (the edges) doesn't change.  Could I have gotten by without
properties?  Sure, but the code wouldn't have any easier to read or
understand, or use.  I'd still need to recompute everything when an edge was
resized.
 
This seems a real world enough example to get the point across:  an API is
like a contract, and once it's engrained, you may want to write adapters
rather than tear into working code.  Adapters aren't the same as properties,
but they're another piece of the theory/nomenclature, and their
implementation may *include* using properties.

Another real world example:  you go to a foreign country and the electrical
sockets are different.  Your appliance would work, if only you could plug it
in.  Do we go out and buy wire cutters, strip off the plug and attach a new
one?  No, hardly.  We go out and buy an adapter, or bring one with us (like
I did to Gothenburg).  

OO has adapters too, and properties may be a part of that.

OO is about objects and the analogies are with objects in reality.  Do we
have properties in reality?  You go to a bank and withdraw cash from your
ATM.  You (not you personally, because you know better) may imagine banks
have big vaults full of cash, but actually they've loaned out the deposits
and carry rather little cash.  They may need to borrow from a different bank
to cover your withdrawal.  Do you need to care?  No.  You just want the ATM
API to work as usual.  

"Information hiding" means sparing me the details.  In an open source world,
I might be able to see those details if I really cared about them.  In the
case of a private bank, fat chance. 

"Information hiding" in the sense of keeping secrets doesn't get invented
with OO theory and gutting OO theory and/or Python of concepts and tools
because you don't like secrecy is not a good solution -- we want and need
those tools.  

Passing legislation requiring more transparency in banking is where what you
might focus.  You want a better API for monitoring the banks.  And that API
might make use of properties behind the scenes.
 
Kirby




More information about the Edu-sig mailing list