Click here to Skip to main content
15,886,199 members
Please Sign up or sign in to vote.
4.00/5 (7 votes)
See more:
I have two classes named ROAD and PATH
C#
public class ROAD
{
    public string getData()
    {
          return "Marlton Road";
    }
}

public class PATH
{
    public string getData()
    {
          return "Tagore Path";
    }
}

Also I have a function named FETCH() in my Static Void Main

FETCH() contains following code

C#
public returnType FETCH(bool flag)
{
    if(flag)
    {
       ROAD obj=new ROAD();
       return obj;
    }
    else
    {
       PATH obj=new PATH();
       return obj;
    }
}


Now my question is what should be the return type of function FETCH().
Or is there any other way to implement this logic.
Posted
Updated 6-Nov-11 8:03am
v4
Comments
BillWoodruff 28-Oct-11 2:32am    
+5 for this question because it's very 'timely,' for me, since I've been trying to review/improve my understanding of 'best practices' in regard to 'factory classes' ... and I do believe the essence of this question is about implementing a factory class.

One question: when you ask what should be the return type of 'Fetch:' I think you are asking: how can your classes, Road and Path, be re-defined to use inheritance, and how to get a 'generic constructor' function whose result will NOT require being cast to either Type Road or Path ... correct ?
BillWoodruff 29-Oct-11 4:35am    
Oct. 29. For the sake of 'completeness,' I've posted the code I worked up using an Abstract class rather than an Interface here. Also, I wanted to post a broad question, on the C# forum, about the implications of using Abstract rather than Interface for a class factory: that question has been posted: http://www.codeproject.com/Messages/4064938/Casting-to-Abstract-parent-rather-than-casting-to-.aspx

Thanks to all for a most illuminating question, and replies !

You can handle this in some ways.

One way to do this is to return an object.
Then in the caller, simply check if the return type is PATH or ROAD.

The other option could be to use an interface if there is some common functionality between the two methods. Implement this interface in both these classes (ROAD and PATH). Return the interface type in the FETCH method.
 
Share this answer
 
Comments
Mehdi Gholam 28-Oct-11 2:01am    
My 5!, I have added more details.
Abhinav S 28-Oct-11 4:38am    
Thank you.
BillWoodruff 28-Oct-11 2:29am    
+5 Abhinav-ji, If you would care to say a little more about the second technique you mention, of returning the interface type, I would really appreciate a brief response (or a link to a source where I could review that technique).

I seem to have a 'cognitive deficit' in the area of 'Interfaces' :)

thanks, Bill
Abhinav S 28-Oct-11 4:43am    
Crude example - may not be exactly compiling but should give you an idea.

nterface IMyInterface
{
string getData();
}
public class ROAD
:IMyInterface
{
public string getData()
{
return "Marlton Road";
}
}

public class PATH
:IMyInterface
{
public string getData()
{
return "Tagore Path";
}
}
public IMyInterface FETCH(bool flag) { if(flag) { ROAD obj=new ROAD(); return obj; } else { PATH obj=new PATH(); return obj; } }


BillWoodruff 28-Oct-11 5:40am    
Sukria !

Edit: this is fascinating to me: before I saw your example code here, I had implemented a crude prototype using an 'abstract' class as the 'parent' for Road and Path. I used a public static method in the abstract 'mother class' to return new instances.

... and I did not realize ... until seeing your code ... and going back to my prototype, and setting a breakpoint ... and examining the returned classes ... that in returning the created classes as Types of the abstract class ... I was achieving the same result as if I had cast them to an interface using the technique you show !

I had no idea this was possible, and I do think this is a case of "monkeys coming up with Shakespeare" :)

So, thanks again, for a most interesting intellectual adventure !
Generally what you are doing is a bad idea and is not object orientated.

To further iterate what Abhinav S has said:

There are three ways you use objects.
1) You don't care what the object type is (return object).
2) You care what the type is to a degree (return a base class).
3) You care about the details of the object (return a specific type).

For example, say you are a handler in a zoo, and your boss says
1) Go and see what we have in cage 19, so you go there and take a picture of the plaque there and give it to your boss. (you return an object and your boss know what to do with it)
2) See if the animal in cage 19 is alive, You call a Animal.isAlive() and check the return is not null.
3) Go and feed the animal in cage 19, so you must know what the animal type is and feed it bananas if it is a monkey, meat if it is a lion etc.
 
Share this answer
 
Comments
BillWoodruff 28-Oct-11 2:44am    
+5 This is a wonderful start for a witty and wise essay on when a 'factory class' is required, or useful, imho.

Forgive my presumption, but I would suggest a fourth "boss says" option as perhaps being relevant to the OP's question:

4. You are tasked with building a cage for a new incoming animal, but we don't know yet if it's for a monkey or a lion, but get busy and do as much as you can so the moment you know whether it's a monkey or a lion, you can be as prepared as possible :)

... note : this fantasy fourth option actually reminds me of some of the weird programming tasks I was involved with long ago, as in the invention of the prototype for what became Acrobat ...

Would you consider me as your 'ghost-writer,' and anonymous colleague, on a book to be, possibly, called "Mehdi's .NET Fables" ? (complete with code examples, of course).

On second thought ... maybe we should re-title that ... for marketing reasons : "Aesop's Fables for C#" Sub-title: "From the Mind of Mehdi Gholam" ? I'm not joking !

best, Bill
Mehdi Gholam 28-Oct-11 2:59am    
Thanks Bill, I would be honored by your literary contributions. :)
Abhinav S 28-Oct-11 4:38am    
My 5.
Mehdi Gholam 28-Oct-11 4:41am    
Thanks
Shmuel Zang 28-Oct-11 5:24am    
My 5.
Above answers covers your Question comprehensively. This type of requirements provides an opportunity to Programmer to improve their Object Oriented skills.

Please consider below "Design Principle" whenever you come across "Object Oriented Programming".

"Program to an interface, not an implementation."
- From the wonderful Book - "Head First Design Patterns" - By wonderful writers Eric Freeman and Elisabeth Freeman.

Lets define an Interface IWay.
C#
public interface IWay
{
  string getData();

}

Now define a Class - Road, which inherits the Interface - IWay.
C#
public class ROAD: IWay
{
  public string getData()
  {
    return "Marlton Road";
  }
}

Lets define a Class- PATH, which too inherits the Interface - IWay.
C#
public class PATH:IWay
{
  public string getData()
  {
    return "Tagore Path";
  }
}

It's time to declare and define FETCH Method. It will look like below.
C#
public IWay FETCH(bool flag)
{
  IWay objectToReturn = null;
  if (flag)
  {
    objectToReturn = new ROAD();
  }
  else
  {
    objectToReturn = new PATH();
  }

  return objectToReturn;
}

if you observe return Type of Fetch method is Type of Interface IWay. And method Fetch will instantiate object of Interface IWay by either of your Class based on your condition.

One more Design Principle from "Head First Design Patterns" Book is as below.

"No matter where you work, what you're building, or what language you are programming in, what's the one true constant that will be with you always?"

Answer is - CHANGE

Lets assume in future you get one more Entity called as "STREET".

In that case all you have to do is as below.
C#
public class STREET : IWay
{
  public string getData()
  {
    return "Canal Street";
  }
}


Hope this information helps you. :). Thank you for posting such a good Question.

Updated - Reeason to mention name of Book - "Head First Design Patterns" here is to give a sincere credit to wonderful writers Eric Freeman and Elisabeth Freeman for their wonderful "Design Principles".
 
Share this answer
 
v3
Comments
Abhinav S 28-Oct-11 8:24am    
If notice, I've already put a similar example in the comments section of my answer. 5 anyway!
RaisKazi 28-Oct-11 8:27am    
Yes I do noticed that. :) It's perfect too. Just wanted to put it with an example. :) Small Correction in your code needed in function "FETCH". Will add it to your section.
Mehdi Gholam 28-Oct-11 10:33am    
5'ed
RaisKazi 28-Oct-11 10:41am    
Thanks Mehdi. :)
Uday P.Singh 28-Oct-11 15:29pm    
excellent answer 5+
Even though I think this question has been thoroughly answered here, I am going to add my code example to the thread, just in case it might be useful, or even just 'entertaining' as an odd 'curiousity' :) ... and also because it demonstrates using another basis for a class factory than 'Interface.

I also will ask a question on the C# forum regarding the implications of the use of this 'factory class' technique compared to using Interface ... which I'm curious about.

Here's my 'abstract class' based factory:
C#
using System;

namespace Paths
{
    public abstract class PathsBase
    {
        // using an enum for future extensibility
        public enum PathTypeID { RoadPathID = 1, TrailPathID = 2 };

        // looking to the future where instances will not
        // have "hard coded" data
        abstract public string PathData { get; set; }

        // note use of non-abstract static 'factory' method 
        public static PathsBase MakeNewPath(PathTypeID typeOfPath, string privateData)
        {
            // using switch with, again, idea of
            // future extensibility
            switch(typeOfPath)
            {
                case PathTypeID.RoadPathID:
                    return new RoadPath(privateData);
                case PathTypeID.TrailPathID:
                    return new TrailPath(privateData);
                default:
                    return null;
            }
        }
    }

    public class RoadPath: PathsBase
    {
        // ctor
        public RoadPath(string privateData) { PathData = privateData; }
        public override string PathData { get; set; }
    }

    public class TrailPath : PathsBase
    {
        // ctor
        public TrailPath(string privateData) { PathData = privateData; }
        public override string PathData { get; set; }
    }
}
So, let's see how this code is used (here invoked from a button Click event handler on a WinForm):
private void button1_Click(object sender, EventArgs e)
{
    PathsBase newRoad = PathsBase.MakeNewPath(PathsBase.PathTypeID.RoadPathID, "Marlton Court");
    PathsBase newTrail = PathsBase.MakeNewPath(PathsBase.PathTypeID.TrailPathID, "Tagore Path");
}
If you compile and test this code, I suggest you set a breakpoint in the Button click handler, and verify, to your own satisfaction, that the objects the factory returns are, indeed, of the 'right type.'
 
Share this answer
 
v2
Comments
Espen Harlinn 30-Oct-11 12:04pm    
Nice example :)
The whole idea is a typical abuse of OOP. You try to introduce the flag which pretend to play a role of something discriminating classes and replacing already existing and robust OOP dispatching mechanism.

We can discuss what to do instead only if you explain the goal of all this activity. Actually, I would advise that you always explain this goal; it can avoid using wrong ideas any of use can be preoccupied with.

—SA
 
Share this answer
 
Comments
[no name] 6-Nov-11 13:08pm    
5!
Sergey Alexandrovich Kryukov 6-Nov-11 13:30pm    
Thank you, Pranit.
--SA
SAKryukov is right. Your way of writing function is violation of OOPS philosophy. But if you still want to do this, Interface is the way.
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900