Re: Converting from one subclass to another
Re: Converting from one subclass to another
- Subject: Re: Converting from one subclass to another
- From: David Avendasora <email@hidden>
- Date: Wed, 13 Feb 2008 17:06:55 -0500
Alright, maybe I'm doing something completely wrong (yeah, yeah,
Chuck), but this isn't an apples and oranges thing.
They are both nutritional values, for example: "Calories: 120"
The difference between my two subclasses is simply how the value of
the valueQuantity() attribute is derived. In one subclass the user
specifies the amount, and in the other it is calculated from the
components that make up the product that the nutrition information is
tied to. This made me think: different implementations of the same
core object means two subclasses.
I think the best thing I could do is throw the whole inheritance
structure out and simply put an "if" clause on the valueQuantity()
method that returns the calculated value if nutritionValueType()
returns "Calculated", or simply change nutritionValueType() to an
isCalculated() boolean instead.
Just doesn't seem as cool though. But I guess "working" is even cooler.
Dave
On Feb 13, 2008, at 3:57 PM, David Elliott wrote:
Hi David,
I can tell you right now that you're going down a very dangerous
path here.
Consider even simple code like this:
MyObject *foo; // from somewhare
foo.setNutritionValueType(...);
// foo is still the old instance.
When you subclass like this you need to know _before_ you create
the object which subclass it is to have. To do anything else is to
completely defeat the very purpose of subclassing in the first
place. If you are using D2W there are little methods you can use
to provide the user his choice before actually creating the object.
If you are not using D2W then you just ask the user in advance.
One UI pattern I've used is something like this:
Add new: [_] Apple [_] Orange [+]
Where [+] is a regular button to add the new object to the list and
Apple/Orange is a set of radio buttons. You could use a pop-up or
whatever else instead. Or you could create an add button for each
object.
What you cannot do is create a Fruit and then expect to be able to
make it an Apple or an Orange at your whim. It doesn't work that
way. Subclassing _might_ be the appropriate thing to do in your
case but it's a very advanced feature of EOF that you have to plan
for very well.
One other thing. If the attributes are the same regardless of the
type (and by this example, they seem to be) then subclassing is the
wrong thing to do entirely. If you want different behavior for
different nutrition types based on the same set of attributes then
I suggest you break your logic into a separate class.
For example:
class Fruit {
...
static abstract class Calculator {
abstract void doSomething(Fruit fruit);
};
static class AppleCalculator extends Calculator {
...
};
static class OrangeCalculator extends Calculator {
...
};
static NSDictionary _calculatorForType = new NSDictionary(new
String[]
{ "APPLE"
, "ORANGE
}, new Calculator[]
{ new AppleCalculator()
, new OrangeCalculator()
});
...
};
You might even implement a cover method like so:
static Calculator calculatorForType(FruitType ft)
{
return (Calculator)_calculatorForType.valueForKey(ft.fruitTypeCode
());
}
That will get you polymorphism (thus allowing you to avoid nasty
switch or if/elif) without requiring the objects themselves have
their own distinct types.
Note that the above isn't compiled, it's just a general example I
typed straight into this mail. Also note I've been doing more C++
than Java coding lately so I probably have semicolons where I don't
need them.
There's other ways to do it too. For example, you can give each
object its own instance of Calculator in which case it will be
easier to make it a non-static inner class and acually store the
pointer to it as a _calculator i-var or something of the sort.
It all really depends on how much state you need or do not need to
put in the separate Calculator class.
-Dave
On Feb 13, 2008, at 3:26 PM, David Avendasora wrote:
Well, I've got it working, somewhat. I'm creating a new instance
of the other subclass, copy all the attributes and relationships
over, then delete the old instance.
The problem I'm having is that I'm somehow getting two instances
of the target subclass. Maybe someone can look at this code and
tell me what I'm doing wrong.
public void setNutritionValueType(NutritionValueType aValue) {
if (nutritionValueType() == null || aValue == null) {
super.setNutritionValueType(aValue);
} else if (aValue != nutritionValueType()) {
CalculatedNutritionValue nv = new CalculatedNutritionValue();
editingContext().insertObject(nv);
nv.setIsSuspect(isSuspect());
nv.addObjectToBothSidesOfRelationshipWithKey(nutritionBlock(),
"nutritionBlock");
nv.addObjectToBothSidesOfRelationshipWithKey(nutritionElement(),
"nutritionElement");
nv.addObjectToBothSidesOfRelationshipWithKey(aValue,
"nutritionValueType");
nv.setSortOrder(sortOrder());
nv.addObjectToBothSidesOfRelationshipWithKey(unitOfMeasure(),
"unitOfMeasure");
nv.setValueQuantity(valueQuantity());
editingContext().deleteObject(this);
}
}
It seems very simple. I just don't get where I'm getting a second
instance. If I save the EditingContext, I do get two new records
in the DB.
Any guesses? Anyone?
Dave
On Feb 13, 2008, at 3:01 PM, Ken Anderson wrote:
David,
I've been down this path many times, and my current
recommendation is to just have some kind of type on the object
that identifies it as one or the other. I have a situation where
I store the class name of a 'calculator' class in the EO, and
then dynamically call static methods on that class to do the
heavy lifting.
Ken
On Feb 13, 2008, at 11:15 AM, Mike Schrag wrote:
I could just create a new object of the new class and delete
the existing one
yes
What is the best way to get WO to pickup the subclass change
immediately?
Or is this just a bad way of doing things?
yes
Inheritance hierarchy is to be treated like a PK -- It's an
unchanging attribute of an EO. In fact, it's actually part of
the EOGlobalID.
What you're describing is very similar to the Employee vs
Manager modeling problem. The general consensus is that when an
Employee becomes a Manager, it's not changing types, it's
changing Roles, so it's actually a Person=>Role, where Role is
Manager or Employee and you are just changing the relationship,
not the intrinsic type.
You should consider type to be immutable for your own safety and
the safety of those around you. The correct way is to delete
your old class and make a new one, or maintain a relationship to
(something like) a NutrionValueCalculator that changes (if there
is a lot of other state in this object other than just this value).
ms
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Webobjects-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
40anderhome.com
This email sent to email@hidden
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Webobjects-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
40avendasora.com
This email sent to email@hidden
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Webobjects-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Webobjects-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden