Re: Best pattern for similar objects with differences
Re: Best pattern for similar objects with differences
- Subject: Re: Best pattern for similar objects with differences
- From: Ken Thomases <email@hidden>
- Date: Wed, 4 Nov 2009 13:58:10 -0600
On Nov 4, 2009, at 12:47 PM, Paul Bruneau wrote:
I'm in early development of an app (non-core data, NSDocument app)
that will deal with a lot of doors. I have created a door object,
SLDoor, which currently contains all of the properties that might be
used by any of the several types of doors.
To be clear, you have created a door _class_ called "SLDoor" (or so I
assume).
There is a doorType property which is what determines which of the
types of doors a particular instance is.
This means that if you choose a door type, many properties that are
only used by any of the other types will go unused. On the other
hand, it's very good for if the user wants to change the door type--
the properties are all there ready and waiting.
But I did have the idea that I should make SLDoor a superclass of
new classes, one for each type of door. So I would have an
SLFlushDoor, an SLMonumentalDoor, and an SLPlankDoor for example,
all subclasses of SLDoor.
In this way, I can really separate out all kinds of code and
properties that are specific to a certain type of door, while
keeping in the superclass all the properties that are shared among
several or all of the types of door (I'm going to have categories to
handle drawing, material takeoff, pricing, etc for each door type).
So this is very attractive, but I keep worrying about how I would
change a door from one type to another if I utilize these
subclasses. Any ideas the best pattern to use? I can't figure out
how I would take an existing object of say SLFlushDoor and convert
it to an SLMonumentalDoor (and possibly back again) with anything
close to the ease that I currently do it with the doorType property
(but I shudder to think of all the if() statements I would have
strewn through all my code if I stick with this pattern.)
Well, the first thing is to be sure that you really want to enable the
user to change the door type. Does it make sense? What does it mean
to change the door type. What happens to the properties that were
appropriate for the old door type but aren't for the new door type?
What values do you use for the properties of the new door type which
weren't relevant for the old type? Etc.
Can this be better modeled by creating a new door object of the new
type, initializing it with some of the properties of the old door
object, and then releasing the old door object? You would also
replace the old door object with the new one in any collections.
If none of that helps, then you can divide the representation of a
door into two classes. Basically, you end up modeling a door type not
with a name or numeric code value, but with a full-fledged object.
So, your doorType property becomes a pointer to an instance of some
SLDoorType class, or rather a type-specific subclass of SLDoorType.
Any type-specific properties and behaviors would be implemented in
that class. Some SLDoor methods might be implemented by invoking
methods on the doorType object. In many cases, clients of SLDoor
would directly reference, for example,
door.doorType.typeSpecificProperty.
When it comes time to change the type of a door, you replace the
doorType object with a new object representing the new type. If
appropriate, you can initialize the new door-type object with that
subset of properties which it shares with the old door-type object.
Accessing type-specific properties through the doorType property still
presents a problem. Since the doorType property is statically typed
as SLDoorType, which is a generic abstract base class of a hierarchy
of door type classes, the compiler will complain if you attempt to
access type-specific properties using accessors (because the generic
SLDoorType class doesn't implement the type-specific properties). The
Objective-C 2.0 dot syntax is just an alternative way to write
accessor calls, so that runs into the same problem. You can solve
this by accessing type-specific properties using Key-Value Coding. If
you're using Bindings, then that already is based on KVC. Since KVC
relies on the actual dynamic type of the door-type object, you don't
have problems with the compiler complaining that the static type of
doorType doesn't support those properties.
So, assuming that "door" is an instance of SLDoor, you might have code
which looks like [door.doorType
valueForKey:@"someTypeSpecificProperty"] or [door.doorType
setValue:someValue forKey:@"someTypeSpecificProperty"].
Now, what happens if there's an attempt to access a type-specific
property when the door is not of that type? Well, ideally, you'd
avoid that situation. You should carefully examine cases where you
think you need to do that to see if they can't be better implemented
by pushing responsibilities into the type-specific door-type class.
So, if you have a method on SLDoor to compute the cost of a door, and
the cost depends on the door type, don't have -[SLDoor cost] attempt
to query the door type's type-specific properties and then calculate
the cost based on that. Instead, have -[SLDoor cost] add -[self
baseCost] and [self.doorType cost]. The generic SLDoor class computes
the type-insensitive part of the cost and have the door-type-specific
class compute the type-specific part of the cost.
If you can't cleanly avoid accessing type-specific properties -- where
"cleanly" means "without lots of 'if's based on the door type" -- then
you may be able to use KVC's support for undefined keys. The generic
SLDoorType base class might override the -valueForUndefinedKey: and -
setValue:forUndefinedKey: methods to provide some sensible behavior
for when you have to access a type-specific property on doors that
aren't of that type.
This is just one possible approach to this problem. There are
certainly others. You may want to read up about "design patterns",
specifically those applicable to object-oriented programming, for
other ideas.
Cheers,
Ken
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden