Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Python > Re: looking for design pattern name

Reply
Thread Tools

Re: looking for design pattern name

 
 
Raymond Hettinger
Guest
Posts: n/a
 
      07-30-2003

"Andrew Dalke" <(E-Mail Removed)> wrote in message
news:bg1lt6$81g$(E-Mail Removed)...
> I'm looking for the name used for a pattern like what Qt uses for
> it's container hierarchy. I'm doing this design for molecules, so I'll
> use that as my example.
>
> There's a container, in this case, a Molecule. A Molecule has Atoms
> and Bonds. When an Atom, it is passed the parent container as
> part of the constructor, as in
>
> mol = Molecule()
> O1 = Atom(mol, # note the parent in the constructor
> O2 = Atom(mol,
> Bond(O1, O2, 2) # (the parent is implicit - comes from the atoms)


What happens in Bond() if O1 and O2 have different parents?

When O1 is constructed, does mol get informed? IOW, after the
four assignments, does mol know that it has two atoms and double bond?


> I want to compare this to a design like
>
> mol = Molecule()
> O1 = mol.add_atom(
> O2 = mol.add_atom(
> mol.add_bond(O1, O2)
>
> which does not allow a user-derived Atom and Bond class
>
> and one like
>
> mol = Molecule()
> O1 = Atom(
> mol.add_atom(O1)
> O2 = Atom(
> mol.add_atom(O2)
> b = Bond(2)
> mol.add_bond(b)


How does this setup handle:

mol1 = Molecule()
mol2 = Molecule()
b = Bond(2)
mol1.add_bond(b)
mol2.add_bond(b)

Is there any way to detect that the same Atom or Bond
being used in two different molecules?



>
> Anyone have good names for any of these three styles?


Assuming that the first approach operates by constructing
components and notifying parents that it is a new component,
then I would call it the Widget pattern because it operates like
Tk widgets:

root = Tk() # root = Molecule()
b1 = Button(root) # b1 = Atom(root,
b2 = Button(root) # b2 = Atom(root,

In Chapter 2 of The Art of Objects, the second and third
approaches are called Collection Manager and Container.
The key distinction is that a Container only contains the
objects and is not responsible for creating them.

Another idea is to name the patterns after the limitations
inherent in each design. When Atoms are constructed
implicitly, the design does not favor applications
that break-up a molecule and re-attach some of the existing
atoms into new molecules, so call it NoMix or some such.

Still another ideas is to describe a pattern by its
characteristic variant or invariant properties:

* The first approach has components with fixed parents
established at the time of component creation. Call the pattern
SignUp since every new atom or bond has to immediately
signup with an existing parent.

* The second approach has captive components.
This suggests the name MoleculeDriven to cover the idea
that all component atoms or bonds are created from the
molecule, thus assuring there can be no orphan atoms or bonds.

* The third approach allows free mixing of components.
This is suggestive of the name TinkerToy where all the
molecular model components can lay separately on a
table (sticks for bonds and cogwheels for atoms).



Raymond Hettinger


 
Reply With Quote
 
 
 
 
Andrew Dalke
Guest
Posts: n/a
 
      07-30-2003
Raymond Hettinger:
> What happens in Bond() if O1 and O2 have different parents?


Raises an exception - TypeError seems best. Here's the code

class BaseBond:
def __init__(self, atom1, atom2):
parent = atom1.parent
if parent is not atom2.parent:
raise TypeError("atoms have different parents")
if atom1 is atom2:
raise TypeError("cannot bond an atom to itself")
for b, xatom in atom1.xiter():
if xatom is atom2:
raise TypeError("bond already exists")

self.parent = parent
self.atoms = ImmutableSet([atom1, atom2])

parent._add_bond(self, atom1, atom2)



> When O1 is constructed, does mol get informed? IOW, after the
> four assignments, does mol know that it has two atoms and double bond?


Yes. See http://mgldev.scripps.edu/CRBM/Members/dalke and more
specifically
http://mgldev.scripps.edu/CRBM/Membe...ons-2003-07-23
(where the above code came from). Here's one possible Atom constructor

class BaseAtom:
def __init__(self, parent):
self.parent = parent
self.bonds = Set()
parent._add_atom(self)

In both the Atom and Bond, the object sets up its own data, then tells
the Molecule that it exists. The Molecule tells the other objects about
the new instance.


> How does this setup handle:
>
> mol1 = Molecule()
> mol2 = Molecule()
> b = Bond(2)
> mol1.add_bond(b)
> mol2.add_bond(b)


(Oops! My original code forgot to tell which atoms the bond code to.)

Presumably the add_bond method sets a "parent" instance in actual bond.
That means when the bond is created, bond.parent is None, then after
mol1.add_bond(b), bond.parent is mol1 and trying to do a mol2.add_bond(b)
will raise an exception because bond.parent is not None and bond.parent
is not b1.

> Is there any way to detect that the same Atom or Bond
> being used in two different molecules?


There must be, otherwise there get to be all sorts of bizarre
behaviours. The best approach seems to be using a 'parent'
attribute in the Atom/Bond. My "parent in constructor" approach
means that obj.parent can never be None, which I like. The
atom.setParent(mol) or mol.addAtom(atom) approch, where
container assignment is done after construction, seems prefered
by some.

> Assuming that the first approach operates by constructing
> components and notifying parents that it is a new component,
> then I would call it the Widget pattern because it operates like
> Tk widgets:
>
> root = Tk() # root = Molecule()
> b1 = Button(root) # b1 = Atom(root,
> b2 = Button(root) # b2 = Atom(root,


Ahh, year ago I tried but failed to understand Tk's packing, so
it wasn't until last year when I looked at Qt that I saw this idiom.

'Widget'. Hmmm, okay. I don't think of atoms and bonds as
widgets, but I understand the comparison.

> In Chapter 2 of The Art of Objects, the second and third
> approaches are called Collection Manager and Container.
> The key distinction is that a Container only contains the
> objects and is not responsible for creating them.


I'll see if I can dig up a copy of the book. Thanks for the
pointer.

> Another idea is to name the patterns after the limitations
> inherent in each design. When Atoms are constructed
> implicitly, the design does not favor applications
> that break-up a molecule and re-attach some of the existing
> atoms into new molecules, so call it NoMix or some such.


"Ahh! now see the violence inherent in the system!"
http://bau2.uibk.ac.at/sg/python/Sou...v/violence.wav
(Sorry, but this *is* a Python newsgroup.

Yeah, I was thinking about that limitation yesterday. There are
times when you want to combine two existing structure (eg, adding
waters to a system, or embedding a protein in a membrane) and
since both systems have a different parent it's tricky.

On the other hand, most changes are more complicated than that.
That is, most times people merge to Molecules is not simply to
combine the two sets of component graphs. Usually the merger
is to modify a component of the existing graph.

For example, proteins are made of chains of amino acids. An
amino acid looks like

sidechain
|
C
/ \
amide end [NH3+] C--[O-] carboxyl end
||
O

When two amino acids are merged to from a short protein, they start
like this

sidechain
|
C O
/ \ ||
[NH3+] C--[O-] [NH3+] C--[O-]
|| \ /
O C
|
sidechain

One of the carboxyl oxygens (btw, they are symmetric.
I just drew one of the resonant states) and two of the
hydrogens from the amide combine to form water. The
plus and minus charges cancel out, and a bond forms
between the C and the N.

sidechain
|
C H O
/ \ | ||
[NH3+] C--O--N C--[O-] + H-O-H
|| \ /
O C
|
sidechain

People will want to assemble proteins using the lower-level
graph operations. An obvious way is to supply fragments
as templates and some operations to join them. Eg,

ALA + GLY + PRO + ALA

makes a chain of 4 residues. But this is complicated because
the "+" operation needs to know how to modify the two terminals
to do the join and to get rid of the newly created water.

(Another way is to make the sequence as string then
convert it to a graph, as in: make_molecule("AGPA"). But
it would be nice to build an amino acid as "peptide backbone"
+ "template for the side chain."... except that doesn't work
well for proline. Hmmm.)

Err, I tangented, didn't I.

So, joining molecules is going to be tricky because it isn't
likely a simple graph merge, it will require editing the two
graphs. And because I want templates, I need to copy
an existing graph template before editing it, which means
the NoMix idea isn't that descriptive.

Guess I should write up some use cases, eh?

> Still another ideas is to describe a pattern by its
> characteristic variant or invariant properties:


Sounds like the best approach, given that there doesn't
seem to be a well established name and the 'Widget'
name you suggested is from a too distant domain.

Thanks for all your help!

Andrew
http://www.velocityreviews.com/forums/(E-Mail Removed)


 
Reply With Quote
 
 
 
 
John J. Lee
Guest
Posts: n/a
 
      07-31-2003
"Andrew Dalke" <(E-Mail Removed)> writes:

> Raymond Hettinger:
> > What happens in Bond() if O1 and O2 have different parents?

>
> Raises an exception - TypeError seems best. Here's the code

[...]

Yuck. Doesn't the standard library reserve TypeError for occasions
where the, um, type of an argument is not appropriate? 'Type' does
generally means the interface rather than type(object), but that's
quite different to what you're checking. Checking whether atoms have
different parents surely isn't a type check. Why not ValueError or
your own exception (possibly derived from ValueError)?

[.........]
> Err, I tangented, didn't I.

[...]

"Verbing weirds language", to quote Calvin.




John
 
Reply With Quote
 
Andrew Dalke
Guest
Posts: n/a
 
      07-31-2003
John J. Lee:
> Yuck. Doesn't the standard library reserve TypeError for occasions
> where the, um, type of an argument is not appropriate?


Quoting from the docs,
exception TypeError
Raised when a built-in operation or function is applied to an object of
inappropriate type. The associated value is a string giving details about
the type mismatch.

In addition to your comments, this is not a built-in operation, so it's
the wrong exception.

> Why not ValueError or
> your own exception (possibly derived from ValueError)?


exception ValueError
Raised when a built-in operation or function receives an argument that
has the right type but an inappropriate value, and the situation is not
described by a more precise exception such as IndexError.

Yup, seems reasonable. I'll change. Thanks!

See you at the next Calvinball tournament, Spaceman Lee.

Andrew
(E-Mail Removed)


 
Reply With Quote
 
Ben Finney
Guest
Posts: n/a
 
      07-31-2003
On 31 Jul 2003 19:17:49 +0100, John J. Lee wrote:
> "Andrew Dalke" <(E-Mail Removed)> writes:
>> Err, I tangented, didn't I.

>
> "Verbing weirds language", to quote Calvin.


From my sigmonster:

"First they came for the verbs, and I said nothing, for verbing
weirds language. Then, they arrival for the nouns and I speech
nothing, for I no verbs." -- Peter Ellis

--
\ "I'm beginning to think that life is just one long Yoko Ono |
`\ album; no rhyme or reason, just a lot of incoherent shrieks and |
_o__) then it's over." -- Ian Wolff |
Ben Finney <http://bignose.squidly.org/>
 
Reply With Quote
 
John J. Lee
Guest
Posts: n/a
 
      08-03-2003
"Andrew Dalke" <(E-Mail Removed)> writes:
[...]
> Quoting from the docs,
> exception TypeError
> Raised when a built-in operation or function is applied to an object of
> inappropriate type. The associated value is a string giving details about
> the type mismatch.
>
> In addition to your comments, this is not a built-in operation, so it's
> the wrong exception.

[...]

Hmm, I don't think that's what the docs meant to communicate -- you're
allowed to use it in your non-builtin code. At least, that's what
I've always assumed:


def isstringlike(x):
try: x+""
except: return False
else: return True

class Foo:
def __init__(self, stringy):
if not isstringlike(stringy):
raise TypeError("stringy must be string-like")


I don't see anything in that documentation that says that's bad.


John
 
Reply With Quote
 
Alex Martelli
Guest
Posts: n/a
 
      08-03-2003
John J. Lee wrote:

> "Andrew Dalke" <(E-Mail Removed)> writes:
> [...]
>> Quoting from the docs,
>> exception TypeError
>> Raised when a built-in operation or function is applied to an object
>> of inappropriate type. The associated value is a string giving details
>> about the type mismatch.
>>
>> In addition to your comments, this is not a built-in operation, so it's
>> the wrong exception.

> [...]
>
> Hmm, I don't think that's what the docs meant to communicate -- you're
> allowed to use it in your non-builtin code. At least, that's what
> I've always assumed:


I agree with your interpretation. Lots of NON-builtin code that is
GvR-approved, e.g. throughout the Python libraries, happily raises such
exceptions as TypeError, so it does seem that the above-quoted para
must NOT be read as "Raised ONLY when a built-in" (etc) but rather
as "Raised (among other circumstances) when a built-in" (etc).


Alex

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
C++ and design Pattern (Composite design Pattern ) Pallav singh C++ 1 01-22-2012 10:48 PM
C++ and design Pattern (Composite design Pattern ) Pallav singh C++ 0 01-22-2012 10:26 PM
C++ and design Pattern (Composite design Pattern ) Pallav singh C++ 0 01-22-2012 10:25 PM
May I have a example of design pattern of "composite", I still feel fuzzy after reading book of Addison-Wesley's"design pattern " jones9413@yahoo.com C++ 1 08-31-2007 04:09 AM
documents related to factory design pattern and Abstract foctory pattern. sunny C++ 1 12-07-2006 04:26 AM



Advertisments