Dynamic casting

J

Jon Shemitz

mfc said:
Suppose I have a Cookie class and a Factory Class. There are many types of
Cookies and maybe one or more Factories with a ProcessCookie Method. Suppose
all the PutInBox method does is decide what colour box to put the cookie
into. But since the colour of the box depends on whatever Factory is boxing
them (Different branding etc) the PutInBox method can't be in the Cookie
class and has to be in the Factory class. The problem is pretty soon the if
statment to decide what PutInBox method to call will be huge. What I need is
so way to dynamically cast the cookie to the right PutInBox method. Is that
possible? Something on the lines of PutInBox((typeof(cookie)) cookie)

There really isn't any way to do exactly what you describe. Probably
the closest is to use Reflection to find the PutInBox overload that
best fits the cookie type:

// neither compiled nor tested
public void ProcessCookie(Cookie cookie)
{
Type FactoryType = GetType(); // or typeof(Factory)
MethodInfo Processor = FactoryType.GetMethod(
"PutInBox",
new Type[] {cookie.GetType()} );
Processor.Invoke(this, new object[] {cookie});
}
 
M

mfc

Suppose I have a Cookie class and a Factory Class. There are many types of
Cookies and maybe one or more Factories with a ProcessCookie Method. Suppose
all the PutInBox method does is decide what colour box to put the cookie
into. But since the colour of the box depends on whatever Factory is boxing
them (Different branding etc) the PutInBox method can't be in the Cookie
class and has to be in the Factory class. The problem is pretty soon the if
statment to decide what PutInBox method to call will be huge. What I need is
so way to dynamically cast the cookie to the right PutInBox method. Is that
possible? Something on the lines of PutInBox((typeof(cookie)) cookie)



Class Cookie {
}

Class ChocolateChipCookie : Cookie {
}

Class HazelNutCookie : Cookie {
}

etc etc....

Class Factory {
public void ProcessCookie(Cookie cookie) {
if (cookie is ChocolateChipCookie ) {
PutInBox(cookie as ChocolateChipCookie);
} else if (cookie is HazelNutCookie) {
PutInBox(cookie as HazelNutCookie);
}
etc etc...
}

protected void PutInBox(ChocolateChipCookie cookie) {
}

protected void PutInBox(HazelNutCookie cookie) {
}
}
 
D

Dave Sexton

Hi,

If you break down the problem further, I think you'll find that you don't
actually need reflection.

Since branding depends not only on the factory, but the Type of the Cookie
as well, then the Cookie class itself should provide the Type-related
information on which branding depends. You have to analyze the business
requirements and choose the appropriate attributes for your business
objects:

abstract class Cookie
{
public abstract bool HasChocolate { get; }
public abstract Color LabelColor { get; }
}

class ChocolateChipCookie : Cookie
{
public override bool HasChocolate
{
get { return true; }
}

public override Color LabelColor
{
get { return Color.Tan; }
}
}

class HazelNutCookie : Cookie
{
public override bool HasChocolate
{
get { return false; }
}

public override Color LabelColor
{
get { return Color.Yellow; }
}
}

abstract class Factory
{
public abstract Box PackageCookie(Cookie cookie);
}

class NewYorkFactory : Factory
{
public override Box PackageCookie(Cookie cookie)
{
return new Box("New York", cookie.LabelColor,
(cookie.HasChocolate)
? Color.Black
: Color.Red);
}
}

class Box
{
public Color LabelColor, PackageColor;
public string Label;

public Box(string label, Color labelColor, Color packageColor)
{
Label = label;
LabelColor = labelColor;
PackageColor = packageColor;
}
}

It might not sound right, at first, to have the LabelColor provided by the
Cookie class; however, you have clearly established a dependency on the Type
of the Cookie for branding requirements, so it makes sense that the Cookie
will provide the Type-related information that the Factory needs.
Otherwise, if you use reflection, your design will not be OO.

If this doesn't seem correct to you, then think about renaming Cookie to
CookiePackagingInfo, for example :)
 
B

Bruce Wood

Dave said:
Hi,

If you break down the problem further, I think you'll find that you don't
actually need reflection.

Since branding depends not only on the factory, but the Type of the Cookie
as well, then the Cookie class itself should provide the Type-related
information on which branding depends. You have to analyze the business
requirements and choose the appropriate attributes for your business
objects:

abstract class Cookie
{
public abstract bool HasChocolate { get; }
public abstract Color LabelColor { get; }
}

class ChocolateChipCookie : Cookie
{
public override bool HasChocolate
{
get { return true; }
}

public override Color LabelColor
{
get { return Color.Tan; }
}
}

class HazelNutCookie : Cookie
{
public override bool HasChocolate
{
get { return false; }
}

public override Color LabelColor
{
get { return Color.Yellow; }
}
}

abstract class Factory
{
public abstract Box PackageCookie(Cookie cookie);
}

class NewYorkFactory : Factory
{
public override Box PackageCookie(Cookie cookie)
{
return new Box("New York", cookie.LabelColor,
(cookie.HasChocolate)
? Color.Black
: Color.Red);
}
}

class Box
{
public Color LabelColor, PackageColor;
public string Label;

public Box(string label, Color labelColor, Color packageColor)
{
Label = label;
LabelColor = labelColor;
PackageColor = packageColor;
}
}

It might not sound right, at first, to have the LabelColor provided by the
Cookie class; however, you have clearly established a dependency on the Type
of the Cookie for branding requirements, so it makes sense that the Cookie
will provide the Type-related information that the Factory needs.
Otherwise, if you use reflection, your design will not be OO.

If this doesn't seem correct to you, then think about renaming Cookie to
CookiePackagingInfo, for example :)

Here is another suggestion:

If the packaging for a cookie at a particular factory is truly
arbitrary... that is, it doesn't depend upon any qualities of the
cookie, just on the cookie type itself, then what you have is a classic
example of a cross-tab: on one access you have types of cookies, on the
other you have factories. (More properly, I would think, you would have
_markets_, because one factory might package a cookie in several
different ways for several different markets, but we'll stick with your
stated requirements....)

Now, you've used inheritance to create different cookies and different
factories, but I have to wonder where that data comes from at the
outset. Inheritance is usually best for creating things that differ in
their fundamentals, not for expressing superficial differences. Is a
chocolate chip cookie so fundamentally different from a peanut butter
cookie that it needs its own class? Or are they the same class with
different ingredients?

The question, stated another way, is whether you distinguish between
cookies based on their formal types (class names) or based on some
unique identification of the cookie type (a UID from a database, for
example). In the second case, the cross-tab is easy to make: you just
create a class called CookieFactoryBoxType or something like that, and
it maintains a two-dimensional array of cookies versus factories with a
box type stored in each location. In effect, it's a Factory pattern
with two inputs (cookie and factory) and one output (box): give me the
cookie type and the factory and I'll give you a box to put it in.

If you distinguish between cookies based on class, then you should be
able to have the cookie Type as one index into the table, and the same
for factories.

Maintaining the table is a whole other question, and depends upon your
requirements. Even if it's hard-coded, it will be easier to maintain
than a code solution, I would think.
 
B

Bruce Wood

Bruce said:
...then what you have is a classic
example of a cross-tab: on one access you have types of cookies, on the
other you have factories.

....on one AXIS you have...

Sorry. I'm having a Monday morning on Tuesday....
 
D

Dave Sexton

Hi Bruce,

I like your ideas as well. Your take on this problem does raise valid
concerns about whether the domain for the attributes I used in my examples
are fixed or variable. Given the data, it seems likely that some of it
would be variable and stored in a relation database, such as "HasChocolate"
and "LabelColor". The OP stated, "There are many types of Cookies", which
leads me to believe that the example provided with multiple Cookie types is
probably a bad design according to the requirements stated thus far.

In my example, "NewYorkFactory" assumes that the OP is coding against a
strict requirement for a Factory in New York (the OP hinted at a fixed
factory domain). But if "City" is in a variable domain determined to be an
attribute on an entity named, "Factory", then I'd suggest that only one
Factory implementation is required with a property named, "City". My code
could be updated by replacing the
string literal, "New York" with the value of the property, City, and the
"NewYorkFactory" implementation could be replaced with the simpler,
"Factory" class (removing the abstract modifier, of course).

In your cross-tab idea the assumption that branding depends on a particular
factory City, for example, and a particular Cookie ID or Name, is probably a
good one. However, in that case it would make sense to a have a relational
table that matches cities to cookies and provides the related attributes
used for branding, such as the appropriate PackageColor, LabelColor and
Label text. In that case, an instance of the Factory class could still
produce a Box for the specified Cookie, simply by looking up the appropriate
information from that table, without the use of a CookieFactoryBoxType class
;)

If the OP posts some detailed requirements I think that we could provide a
much more robust and useful solution.

I think we agree that reflection is probably not required or recommended,
correct?
 
D

Dave Sexton

Hi Bruce,

No problem - I read it as AXIS :)

I'm having a Leap year on Friday. (whatever that means)
 
D

Dave Sexton

Hi,

Thanks for the link.

Admittedly, I haven't read the entire article, but from the few pages that I
read it seems like the author prefers a language that is somewhere between
scripting and OOP.

In your case, using C#, you have design patterns at your disposal to
alleviate any need for reflection or "dynamic casting", as Bruce and I have
suggested through example. A relational database may be used to help your
code to be OO as well, as I suggested in my last response.

If you want to research design patterns further, here are some links:

"Data & object factory" (GoF)
http://www.dofactory.com/Patterns/Patterns.aspx

"Microsoft Patterns & Practices"
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpatterns/html/MSpatterns.asp

"PatternShare Community Home Page"
http://www.patternshare.org/

"People Projects And Patterns" (a wiki)
http://c2.com/cgi/wiki?PeopleProjectsAndPatterns
 

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

Top