[Tutor] class design - base classes with optional properties?

Alan Gauld alan.gauld at btinternet.com
Fri Jan 23 00:24:22 CET 2009


"Marcus Goldfish" <magoldfish at gmail.com> wrote

> I'm trying to design a base class for a hierarchy.  The properties I 
> want to
> specify for the base class depend on the values of other properties 
> of the
> base class.

Don't worry so much about the properties, the important thing to focus 
on
in your base classes is the behaviour. What exactly will these classes 
do?
What methods will they have? How will they be overridden in your
subclasses.

Ideally the properties are invisible to the users of the class so the
interactions of the properties should all be controlled by the
methods.

> class FoodProcessor:
>    "Model for a kitchen appliance food processor"
>    speed_settings     # example [1, 2, 3, 4]
>    blade_settings      # example ["slice", "grate", "grind"]
>    slice_thickness     # example ["thin", "thick"], but only if
> blade_setting is "slice"
>
> it only make sense to have the slice_thickness property set when
> blade_settings = "slice"; otherwise, it would be preferable to only 
> define
> the speed_settings and blade_settings properties.  For example:

So create a method to initialise slicing which sets both properties
(with appropriate default values if you like)

Similarly define methods for grating and grinding. Think about
what you want to *do* with a class not what you want to store.
The function should dictate the attributes.

> class ProcessorA(FoodProcessor):
>    "A slicing-only processor"
>    speed_settings = [1, 2, 3, 4]
>    blade_settings = "slice"
>    slice_thickness = ["thin", "thick"]
>
> class ProcessorB(FoodProcessor):
>    "A non-slicing processor"
>    speed_settings = [1,2,3,4]
>    blade_settings = ["grate", "grind"]
>    slice_thickness = None

Unless this is a multi function food processor I'd probably
go for a heirarchy of

FoodProcessor
    Slicer
    Grater
    Grinder

In fact I might do that anyway and then create
MultiFunction as a subclass of of all 3 food
processors...

class MultiFunction(Slicer, Grater, Grinder):
   etc...

Remember that ideally nothing outside the class should be manipulating
the attributes directly, everything should be done by sending messages
(ie calling methods) to the objects. The fact that you want a 
heirarchy
suggests that you have some form of polymorphic operations to be
performed? What are those operations at the abstract FoodProcessor
level?

It is actually very common that the root object in a heirarchy has 
very
few if any attributes but will have all the methods needed for the 
concept
to work. As you subclass you add attributes to support the subclass
specific implementation of the methods.

If you truly want a multi purpose mixer and don't want to subclass 
from
all 3 types then you could have a changeBlade method that specifies
the blade type and any additional attributes. The Blades could even
be a class heirarchy in their own right:

Blade
    Slicer
    Grinder
    Grater

# create a new processor with initially a slicer blade
p = FoodProcessor(Slicer(thickness))
p..process(spam)
p.changeBlade(Grater(granularity))
p.process(Cheese(5, 'oz'))    # uses a Cheese object with weight in 
ounces...

and so on...

But the only real solution will depend on what you intend to do with
your classes. Think about how you want to write the client code.
Think about doing that using method calls rather than manipulating
the inner data. That way you can leverage polymorphism to your
advantage.

HTH,

-- 
Alan Gauld
Author of the Learn to Program web site
http://www.freenetpages.co.uk/hp/alan.gauld 




More information about the Tutor mailing list