A design problem I met again and again.

P

paul

Ò»Ê×Ê« said:
Consolidate existing functions?

I've thought about it.

For example, I have two functions:

#=========================

def startXXX(id):
pass

def startYYY(id):
pass
#=========================

I could turn it into one:

#=========================
def start(type, id):
if(type == "XXX"):
pass
else if(type == "YYY"):
pass
#=========================

But isn't the first style more clear for my code's user?
Depends ;)

There are more ways to structure code than using classes. To avoid the
if-elif-elif-elif-else problem you could start using a dispatch table
which maps types to functions (fex using a dict)

start_methods = {
'type1': startXX,
'type2': startYY,
}

def start(type, id):
func = start_methods.get(type, None)
if func:
func(id)
else:
raise ...

Or maybe look at trac's (http://trac.edgewall.com) use of Components and
Interfaces. Very lightweight and modular. You can start reading here:
http://trac.edgewall.org/browser/trunk/trac/core.py

cheers
Paul
 
C

Carl Banks

Consolidate existing functions?

I've thought about it.

For example, I have two functions:

#=========================

def startXXX(id):
pass

def startYYY(id):
pass
#=========================

I could turn it into one:

#=========================
def start(type, id):
if(type == "XXX"):
pass
else if(type == "YYY"):
pass
#=========================

But isn't the first style more clear for my code's user?

Not necessarily, especially if the user wants to dynamically choose
which start*** function to call.

I have one more suggestion. Consider whether there are groups of
methods that are used together but aren't used with other groups of
functions. For instance, maybe there is a group of methods that can
only be called after a call to startXXX. If that's the case, you
might want to separate those groups into different classes. The
branched-off class would then act as a sort of session handler.

A piece of user code that looked like this (where sc is an instance of
your enormous class):

sc.startX()
sc.send_data_via_X()
sc.receive_data_via_X()
sc.stopX()

might look like this after you factor it out:

session = sc.startX() # creates and returns a new XSession object
session.send_data() # these are methods of the XSession
session.receive_data()
session.stop()


Any methods that are callable any time, you can retain in the big
class, or put in a base class of all the sessions.


Carl Banks
 
M

Michele Simionato

A piece of user code that looked like this (where sc is an instance of
your enormous class):

sc.startX()
sc.send_data_via_X()
sc.receive_data_via_X()
sc.stopX()

might look like this after you factor it out:

session = sc.startX()  # creates and returns a new XSession object
session.send_data()    # these are methods of the XSession
session.receive_data()
session.stop()

Any methods that are callable any time, you can retain in the big
class, or put in a base class of all the sessions.

That's good advice. A typical refactoring technique when
working with blob classes is to extract groups of methods
with commmon functionality, put them in a helper
class, make a helper object and pass it to the
original blob. In other words, tp split the blob
object as a composition of small logically independent
objects. BTW, is there anybody in this lists that
can suggest good books about refactoring in Python?
There are plenty of books about refactoring for Java
and C++ but on top of my mind I cannot think of a Python
book right now.
 
Ò

Ò»Ê×Ê«

That's clever. I never thought of that. Not only something concrete,
like people, could be class, but a procedure, like a Session, could
also be a Class.

Thanks for you all who replied. I learned a lot from this thread and
I even made some notes of all your advices because I think I might
review them many times in my future work.
 
D

Dennis Lee Bieber

That's clever. I never thought of that. Not only something concrete,
like people, could be class, but a procedure, like a Session, could
also be a Class.
Note that, if you go by the old OOAD starting point... "Session" is
noun, not a procedure. Nouns are candidates for classes; verbs are
candidates for methods/procedures (and adjectives may imply something
that qualifies as an attribute: "under condition <x> the indicator shall
transistion from green to red" => indicator/noun -> possible class;
green&red -> apparently a color attribute; transition qualified by
condition -> method)

Anything that has a state (ie, a collection of attributes that
describe how this instance differs from another instance) is a candidate
for becoming an object/class. Though I will admit in my old classes I
took a strange route with the "use OOAD to design a calculator"... 1) I
chose RPN notation; 2) I did not use an ALU -- instead I embedded the
operation(s) into individual "keys". This way, adding new functionality
means just adding new "keys" -- not adding both keys AND modifying the
ALU. So I had "key", "stack", and "display" interfaces.

"press the 2 key":
get current open entry from stack
left shift digit
append "2"
put result back to stack | (stack) update display

"press + key":
close any open stack entry
pop stack | (stack) shift stack/dup top
pop stack | (stack) shift stack/dup top
add entries
push stack | (stack) update display

Number keys were easy, as all do the same but with a different
"value" attribute -- easy to subclass. Operators are a bit more complex,
essentially being all individual (but subclassed from a master "key" so
they all can be plugged into the system).
--
Wulfraed Dennis Lee Bieber KD6MOG
(e-mail address removed) (e-mail address removed)
HTTP://wlfraed.home.netcom.com/
(Bestiaria Support Staff: (e-mail address removed))
HTTP://www.bestiaria.com/
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,999
Messages
2,570,244
Members
46,838
Latest member
KandiceChi

Latest Threads

Top