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 (Cocoa-dev@lists.apple.com)

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:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Reply via email to