473,578 Members | 3,001 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

OO refactoring trial ??

OO refactoring trial
=============== =====
Following is a simple trial structure of a refactoring (top-down to OO)
learning exercise I'm doing. Whether you call it a Factory pattern, COR
pattern, or some hinze 57, I don't know what class to use till run time and
I'm trying to avoid a lengthy "if" sequence, the test sequence is important,
and to avoid code duplication I'll be using code objects in the "doit"
methods.

You've already given me many good ideas in previous threads and this is where
it got you :~) This works, but would you please tell me:
1) What you don't like about the approach
2) The implications of using this in a recursive approach (referenced from
but outside the recursive function) and if the decorators help with such.
3) Any other comments you might offer

Thank you,
Lee C
=========== ootest.py
============
class MF(object):
@staticmethod
def findit(t):
for it in MF.__subclasses __():
if it.testit(t):
return it().doit

class A(MF):
@staticmethod
def testit(tv):
if tv == 'relates to A':
return True
else:
return False

def doit(self):
print '# did A #'

class B(MF):
@staticmethod
def testit(tv):
if tv == 'relates to B':
return True
else:
return False

def doit(self):
print '# did B #'

mydoit = MF.findit('rela tes to B')
mydoit()

mydoit = MF.findit('rela tes to A')
mydoit()

======== Test run ==============
Python 2.4.1 (#2, Mar 31 2005, 00:05:10)
[GCC 3.3 20030304 (Apple Computer, Inc. build 1666)]
Type "help", "copyright" , "credits" or "license" for more information.
import ootest # did B #
# did A #


Jul 19 '05 #1
10 1503
Chinook wrote:
3) Any other comments you might offer if*tv*==*'relat es*to*A':
return*True
else:
return*False


Make that

return tv == 'relates to A'

lest your zen master hit you.

Peter
Jul 19 '05 #2
On Tue, 28 Jun 2005 02:22:13 -0400, Peter Otten wrote
(in article <d9************ *@news.t-online.com>):
Chinook wrote:
3) Any other comments you might offer

if*tv*==*'relat es*to*A':
return*True
else:
return*False


Make that

return tv == 'relates to A'

lest your zen master hit you.

Peter


Thank you Peter,

So wrapped up in the OO I overlooked the simpler aspects.

Lee C
Jul 19 '05 #3
Lee,

Interesting idea, but I think the technique of "inherit from MF to
automatically add class to the test chain" is a gimmick that wont
scale.

Here are some things to consider:

- I'm not keen on the coupling of forcing your A,B,etc. classes to
inherit from MF. Especially in a duck-typing language like Python, it
adds no value, the subclasses receive no default behavior from their
superclass, and I'm not keen on using the inheritance hierarchy to
register test classes. What is the order of classes returned from
__subclasses__( )? Will you always want this order? Will you always
want all subclasses? If this is part of a library that others will
use, you may not be able to anticipate what subclasses someone else may
stick on to your MF class.

- The list of items should be dynamic in the calling code, not built
statically by your class structure. There's no way to anticipate what
various sequences you will want to evaluate.

- Let's call the MF class "MultiEvaluator ". There are several ways to
evaluate among several alternatives:
. short-circuit, take first match
. best-fit, evaluate all and take best score (assuming the testit
routines return a double or int, as opposed to a bool)

For short-circuiting, say you have a case that will match A, you want
to avoid any processing related to B,C,etc. as possible at test/do
runtime. You *might* be able to do extra work at list construction
time. Consider these two alternative designs:

class MultiEvaluator( object):
def __init__(self, *classes):
self.testClasse s = classes[:]

def findit(self, *args):
for C in self.testClasse s:
testobj = C()
if testobj.testit( args[0]):
testobj.doit()

MultiEvaluator( A,B).findit("re lates to A")

vs.

class MultiEvaluator( object):
def __init__(self, *classes):
self.testClasse s = [ C() for C in classes ]

def findit(self, *args):
for testobj in self.testClasse s:
if testobj.testit( args[0]):
testobj.doit()

MultiEvaluator( A,B).findit("re lates to B")

In the first case, no B class is ever constructed, so if test object
construction is expensive, you might go this route. In the second, A()
and B() are built ahead of time, so the run-time processing is the
fastest - you might choose this if the construction time can be done up
front. The second option may cause problems for multi-threadedness or
re-entrancy with a shared MultiEvaluator, though.

This style of constructing the MultiEvaluator also makes more explicit
(which I hear is better than implicit) what classes you are testing
when creating your MultiEvaluator.

- To make your testit() and doit() code more flexible and more
powerful, I'd pass (*args) to each, as in:

class MultiEvaluator( object):
def __init__(self, *classes):
self.testClasse s = classes[:]

def findit(self, *args):
for C in self.testClasse s:
testobj = C()
if testobj.testit( args):
testobj.doit(ar gs)

- In the interests of flogging OO-ness, you could make MultiEvaluator
into a function object, by changing "findit" to "__call__". Then your
invocation of it would change from:

getObj = MultiEvaluator( A,B)
getObj.findit(" relates to B")

to:

getObj = MultiEvaluator( A,B)
getObj("relates to B")

Although some might claim this is *less* explicit. The purpose of this
is that you could then pass getObj to functional routines like map
(although you could also pass getObj.findit).

Those are my comments off the top of my head. Let us know what you
come up with.

-- Paul

Jul 19 '05 #4
On Tue, 28 Jun 2005 10:22:59 -0400, Paul McGuire wrote
(in article <11************ *********@g43g2 000cwa.googlegr oups.com>):
Lee,

Interesting idea, but I think the technique of "inherit from MF to
automatically add class to the test chain" is a gimmick that wont
scale.

Here are some things to consider:

- I'm not keen on the coupling of forcing your A,B,etc. classes to
inherit from MF. Especially in a duck-typing language like Python, it
adds no value, the subclasses receive no default behavior from their
superclass, and I'm not keen on using the inheritance hierarchy to
register test classes. What is the order of classes returned from
__subclasses__( )? Will you always want this order? Will you always
want all subclasses? If this is part of a library that others will
use, you may not be able to anticipate what subclasses someone else may
stick on to your MF class.
Even though this is an exercise, it is a learning exercise and your points
are taken as pertinent considerations in "real-world" adaptation.

So basically I'm coming from a if:elif:...else : test sequence where the order
of the tests is critical (could be multiple hits and the first should be
taken). My first trial was just to move the "if" sequence to a factory
method. My second trial was to initially create an ordered list of classes
to be tested as in:
class A(object): .... def foo(self):
.... print "I'm A.foo"
.... class B(object): .... def foo(self):
.... print "I'm B.foo"
.... co = [A(), B()]
co[1].foo() I'm B.foo


My third trial is what you are responding to. So in the "real-world" I could
only suggest how someone else might add a test, but just as in the top-down
"if" sequence I could impose no discipline. Even adding a weighting/priority
to test cases (and going through all) is a halfway measure (though possibly a
more explicit one). I think that the consideration of how a test case might
be added in the future is very important - having dug my way through many
other programs.

BTW: Is duck-typing a variation on duct-taping?

- The list of items should be dynamic in the calling code, not built
statically by your class structure. There's no way to anticipate what
various sequences you will want to evaluate.
I was also playing with another exercise involving dynamic test cases where I
thought the ordered list (second trial) would be a potential approach?

- Let's call the MF class "MultiEvaluator ". There are several ways to
evaluate among several alternatives:
. short-circuit, take first match
what I was shooting for in this exercise
. best-fit, evaluate all and take best score (assuming the testit
routines return a double or int, as opposed to a bool)
like my weighted/priority thought?

For short-circuiting, say you have a case that will match A, you want
to avoid any processing related to B,C,etc. as possible at test/do
runtime. You *might* be able to do extra work at list construction
time. Consider these two alternative designs:

class MultiEvaluator( object):
def __init__(self, *classes):
self.testClasse s = classes[:]

def findit(self, *args):
for C in self.testClasse s:
testobj = C()
if testobj.testit( args[0]):
testobj.doit()

MultiEvaluator( A,B).findit("re lates to A")
my only drawback on such would be ME(A,B,...Z).fi ndit(test_data)
Explicit but cumbersome maybe, though no where near as cumbersome as a
lengthy "if" sequence.

vs.

class MultiEvaluator( object):
def __init__(self, *classes):
self.testClasse s = [ C() for C in classes ]

def findit(self, *args):
for testobj in self.testClasse s:
if testobj.testit( args[0]):
testobj.doit()

MultiEvaluator( A,B).findit("re lates to B")

In the first case, no B class is ever constructed, so if test object
construction is expensive, you might go this route. In the second, A()
and B() are built ahead of time, so the run-time processing is the
fastest - you might choose this if the construction time can be done up
front. The second option may cause problems for multi-threadedness or
re-entrancy with a shared MultiEvaluator, though.

This style of constructing the MultiEvaluator also makes more explicit
(which I hear is better than implicit) what classes you are testing
when creating your MultiEvaluator.

- To make your testit() and doit() code more flexible and more
powerful, I'd pass (*args) to each, as in:
The testit() methods do in the full-fledged exercise. The doit() methods
return code objects (but I'm rethinking that).

class MultiEvaluator( object):
def __init__(self, *classes):
self.testClasse s = classes[:]

def findit(self, *args):
for C in self.testClasse s:
testobj = C()
if testobj.testit( args):
testobj.doit(ar gs)
As in my ordered list approach (and what I thought my "cleverly" generated
list would also do before giving it more thought), the idea in this exercise
is to have one list (created once) that all levels of recursion would use.

Your forcing me to use my head :~)

- In the interests of flogging OO-ness, you could make MultiEvaluator
into a function object, by changing "findit" to "__call__". Then your
invocation of it would change from:

getObj = MultiEvaluator( A,B)
getObj.findit(" relates to B")

to:

getObj = MultiEvaluator( A,B)
getObj("relates to B")

Although some might claim this is *less* explicit. The purpose of this
is that you could then pass getObj to functional routines like map
(although you could also pass getObj.findit).

Good point, but my objective is an OO learning exercise. My mind isn't as
flexible as it was back in the 60s :~) so it takes more effort to get a
handle on something new (to me).


Those are my comments off the top of my head. Let us know what you
come up with.

-- Paul


Thank you very much for taking the time to consider and respond,

Lee C

Jul 19 '05 #5
Never mind.

BTW: Is duck-typing a variation on duct-taping?


http://www.rubygarden.org/ruby?DuckTyping

http://en.wikipedia.org/wiki/Duck_typing
Lee C

Jul 19 '05 #6
Paul,

Going back over various material led to another question regarding your
comments.
- I'm not keen on the coupling of forcing your A,B,etc. classes to
inherit from MF. Especially in a duck-typing language like Python, it
adds no value, the subclasses receive no default behavior from their
superclass, and I'm not keen on using the inheritance hierarchy to
register test classes.


The latter (__subclasses__ () bit) I picked up on as a convenience (courtesy
of a suggestion by STeVe) and I understand your point about more explicit
ordering. However, the former seems to take issue with examples like:

http://jamesthornton.com/eckel/TIPython/html/Sect08.htm

or indirectly as a show stopper (using inheritance) as in:

http://www.unc.edu/~mconway/mt_stati...odds_and_ends/

which is more in line with your comments.

Anything more to this than individual preferences? Might it not be more
explicit at least? Anyone?

Thanks,

Lee C

Jul 19 '05 #7
'''
You might find this interesting. Note that the object creation in
main() below could easily be read in from a text file instead,
thus meeting your requirement of not knowing an item's class
until runtime.

Sample output:

{'password': 'Your Password Here', 'type': 'A', 'logonid': 'Your
Logonid Here'}
# did A #
{'ssn': 555555555, 'type': 'B'}
# did B #
{'type': 'BASE', 'address': '501 south street'}
# did BASE #
None
'''

def Create(type = 'BASE', **kwargs):
if type not in _CLASSES:
return None # Or return a default object
obj = _CLASSES[type](type = type, **kwargs)
return obj

class BASE(object):
def __init__(self, **kwargs):
self.__dict__.u pdate(kwargs)
def __str__(self):
return str(self.__dict __)
def doit(self):
print "# did BASE #"

class A(BASE):
def doit(self):
print '# did A #'

class B(BASE):
def doit(self):
print '# did B #'

_CLASSES = {'BASE': BASE, 'A': A, 'B': B}

def main():
obj1 = Create(type = 'A', logonid = 'Your Logonid Here', password =
'Your Password Here')
print obj1
obj1.doit()
obj2 = Create(type = 'B', ssn = 555555555)
print obj2
obj2.doit()
obj3 = Create(address = '501 south street')
print obj3
obj3.doit()
obj4 = Create(type = 'Missing')
print obj4

main()

Jul 19 '05 #8
Lee -

Bruce Eckel's observation:

"the above scaffolding of Obstacle, Player and GameElementFact ory
(which was translated from the Java version of this example) is
unnecessary - it's only required for languages that have static
type checking. As long as the concrete Python classes follow the form
of the required classes, we don't need any base classes..."

is consistent with my "duck-typing" comment that all that is needed of
A,B,etc. is that they provide the necessary testit and doit methods in
the proper form. He also goes on to say that, even if the base classes
were empty, they still provide a useful handle for all of the derived
classes, to indicate they are all common subtypes of "Shape" or
whatever.

I think you were referring to the "Poking Python with a Stick" entry in
the second link. The inheritance of all taunts from Taunt allowed the
author to put some overriding common-to-all-taunts behavior into the
superclass, even if it was just a "sorry, not implemented" exception
into the base Taunt class's tauntTheKnights () method. The idea was to
provide a runtime exception if the needed method had not been
overridden in the subclass. But it also provides a place to put any
other common-to-all-taunts behavior, perhaps a common constructor, or
other common helper methods. I think this is a good use of
inheritance, when the base class actually adds some value to the
architecture, even if it is just Bruce Eckel's empty placeholder base
class. Note also that this author was doing patterns experimentation
in both Python and Java. I envision him writing the factory's
getInstance() method in Java, and having to declare its return value
type. In this case Java really drives you to having all possible
return values derive from a common base class, so that you can define
the method as:

Taunt getInstance(str ing tauntTypeTag) { ...

which is a bit easier to deal with than just declaring that getInstance
returns an object, and then having to cast it - in fact, if there were
no common base type, it would be problematic to know just what to cast
it to.

But Python does not require this sort of type rigidity. In your code,
the only requirement is that each class A,B,etc. have testit and doit
methods - they have to walk and talk like ducks, they don't need to
*be* ducks. My point in an earlier post was, I think many current
design patterns were born out of the C++ and Java worlds, and may be
overly restrictive for a comparable implementation in Python.

One step you might take in the MultiEvaluator constructor is to
validate the provided classes on input, so that you don't have to
exhaustively test all A thru Z classes before finding out that you
misspelled Z's doit method as "dooit". This goes one better than the
abstract subclass's "you forgot to override me" method implementation.

In sum, both of the links you sent used examples that had inheritance
hierarchies where the base class provided some contribution and
commonality among the derived classes. TauntArthur "is-a" Taunt,
TauntGalahad "is-a" Taunt. It really does look like the Factory
pattern should return objects that share a common base class. But in
Python, that common base class can also be just "something that walks
like a duck."

-- Paul

Jul 19 '05 #9
On Tue, 28 Jun 2005 23:23:43 -0400, Kamilche wrote
(in article <11************ *********@g14g2 000cwa.googlegr oups.com>):
'''
You might find this interesting. Note that the object creation in
main() below could easily be read in from a text file instead,
thus meeting your requirement of not knowing an item's class
until runtime.

Sample output:

{'password': 'Your Password Here', 'type': 'A', 'logonid': 'Your
Logonid Here'}
# did A #
{'ssn': 555555555, 'type': 'B'}
# did B #
{'type': 'BASE', 'address': '501 south street'}
# did BASE #
None
'''

def Create(type = 'BASE', **kwargs):
if type not in _CLASSES:
return None # Or return a default object
obj = _CLASSES[type](type = type, **kwargs)
return obj

class BASE(object):
def __init__(self, **kwargs):
self.__dict__.u pdate(kwargs)
def __str__(self):
return str(self.__dict __)
def doit(self):
print "# did BASE #"

class A(BASE):
def doit(self):
print '# did A #'

class B(BASE):
def doit(self):
print '# did B #'

_CLASSES = {'BASE': BASE, 'A': A, 'B': B}

def main():
obj1 = Create(type = 'A', logonid = 'Your Logonid Here', password = 'Your Password Here')
print obj1
obj1.doit()
obj2 = Create(type = 'B', ssn = 555555555)
print obj2
obj2.doit()
obj3 = Create(address = '501 south street')
print obj3
obj3.doit()
obj4 = Create(type = 'Missing')
print obj4

main()


Kamilche,

Yes it is interesting and explicit, thank you.

What I was not clear enough about though, is that at runtime the class object
creation depends on the information being processed. That is, the context
and type of node in the recursed tree. That's why in my trial the potential
classes all included a "testit" method and the order of testing is important.
Beyond that the "doit" methods all have some varying duplicated expressions,
so I was constructing their functionality with code objects. However, in
going back over researched material after Paul's comments I noticed another
technique that might be better in creating functionality and have to study it
further.

Thanks for the sample,

Lee C
Jul 19 '05 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

9
2023
by: Peter Dembinski | last post by:
I am trying to write Master Thesis on refactoring Python code. Where should I look for information? -- http://www.dembiŮski.prv.pl
4
1593
by: | last post by:
Hi, Refactoring a winform causes problems if moving this form to a subdirectory in the same project. What is the workaround for this and will this be fixed in future? Thanks /BOB
0
1965
by: Andre Baresel | last post by:
Hello together, just a year ago I was searching arround for a tool supporting refactoring for c++. I've seen implementations for java and was impressed how an IDE can help with such a feature. Just rename classes / member / parameter with a mouse click. reduce the size of a method by transforming parts of it into a seperate
2
2094
by: Sachin Garg | last post by:
Hi, I was trying to find (like many others here) a tool for refactoring C++ code as I have lately been noticing that I spend most of my coding time doing refactoring and some refactoring which I skip, due to the enormous effort it seems to require, usually comes back to me with larger costs. I read a few comp.lang.c++ threads over past...
6
3341
by: Dean Ware | last post by:
Hi, I am part way through developing a C++ application. I am developing it on my own and using VC++ 6.0. I am now at the stage where I wish to start tidying up my code. I have lots of superfluous code that is hard to be sure about removing. For example, I have classes that are ONLY used in methods that are never
8
2006
by: Frank Rizzo | last post by:
I keep hearing this term thrown around. What does it mean in the context of code? Can someone provide a definition and example using concrete code? Thanks.
15
4381
by: Simon Cooke | last post by:
Does anyone know of any tools for refactoring header files? We're using a third party codebase at work, and pretty much every file includes a 50Mb precompiled header file. I'm looking for a tool that will let us figure out which header files are actually needed by each .cpp, and allow us to break this up so that we're not including the world...
2
1809
by: HendrikLeder | last post by:
Hello everybody :-) Next year I`ll write my diploma in computer science for business (It`s a degree in Germany) and I`ve some questions about the topic. The diploma will handle about refactoring of xml-schemes and a transformation of all instances (the xml-documents) with XSLT-scripts. The idea of the diploma is, that in nearly every...
9
1376
by: Rory Becker | last post by:
I guess it's possible I'm imagining it, but I thought I heard somewhere that DevExpress did some kind of deal to get MVPs a free copy of Coderush (Which includes RefactorPro) If this info is correct then it's also quite old, but I have this back of my mind idea that they did some kind of promotional deal. Can't remember, I'll look into...
0
7779
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language...
0
8126
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. ...
0
8291
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that...
1
7874
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For...
0
8150
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the...
1
5664
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Duprť who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes...
0
3786
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in...
1
1391
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
0
1114
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.