One method, several different derived classes, what's best

M

Marcel Overweel

Hi,

I'm wondering if there's a better solution for the following:

I've got a base class called Channel.
Channel is build up mostly out of abstract methods.

A few derived classes, called ComChannel, NetChannel and
ModemChannel contains the actual implementation.

The user of these classes doesn't need to know anything about
the derived classes.

My idea was to give 'Channel' three static methods.
For instance (simplified example, not actual code):

public class Channel
{
static Channel CreateChannel(int a) {...} // returns a ComChannel
static Channel CreateChannel(double a) {...} // returns a NetChannel
static Channel CreateChannel(string a) {...} // returns a ModemChannel
...
other non-static methods and such
}

The derived classes are defined as:
internal class ComChannel : Channel {...}
internal class NetChannel : Channel {...}
internal class ModemChannel : Channel {...}

The class Channel doesn't have a (public) constructor so this forces
the user to call any of the three 'Create...' methods.

Is this a wise design or are there better solutions?

I know I could make the three internal classes public, but then the
user has to decide which class it should instantiate.

The code will be part of an SDK, so I don't want to introduce
classes which are of no concern to the user.
The interface should be as simple as possible.

regards,
Marcel
 
I

Ignacio Machin ( .NET/ C# MVP )

The class Channel doesn't have a (public) constructor so this forces
the user to call any of the three 'Create...' methods.

Is this a wise design or are there better solutions?

It's a good design, the client does not know (nor care) the real type
of the instance being returned.
 
M

Marcel Overweel

Peter Duniho said:
[...]
public class Channel
{
static Channel CreateChannel(int a) {...} // returns a ComChannel
static Channel CreateChannel(double a) {...} // returns a NetChannel
static Channel CreateChannel(string a) {...} // returns a ModemChannel
...
other non-static methods and such
}

The derived classes are defined as:
internal class ComChannel : Channel {...}
internal class NetChannel : Channel {...}
internal class ModemChannel : Channel {...}

The class Channel doesn't have a (public) constructor so this forces
the user to call any of the three 'Create...' methods.

Actually, the presence of abstract members prevents anyone from
instantiating Channel directly, even if it did have a public constructor
(though, it's possible C# only allows protected constructors for abstract
classes...I don't remember off the top of my head).
Is this a wise design or are there better solutions?

Not only is the design workable, as Ignacio says, what you're doing is a
form of the "factory" design pattern and is actually a reasonably common
approach to doing what you're doing.

The one thing I might change is to not make the kind of Channel created
depend solely on the method overload you're using. It's not clear from
your post how these arguments to the method vary, but it's hard to see why
"string" shouldn't be a valid argument to all the factory methods (where
it's parsed to some other format for Com and Net), nor why Com gets an
"int" and Net gets a "double".

So while I see the attraction to having just the one method name, it seems
to me that in spite of your desire to not require the user "to decide
which class it should instantiate", it seems to me that the user already
needs to know _something_ about the differences in instantiation methods,
and it would wise to make the selection process more general-purpose and
explicit.

Good point.

So far, it is:
a) a set of parameters for an rs232 comm. line
b) the same as (a) plus a telephone number for modem connection
c) a tcp/ip address and port number

I didn't want to put so much variables in the example, thought just showing
three different types would be more clear.
The factory pattern is still a good one; I'm not saying you would
necessarily want to make the sub-classes public. But, you should probably
provide for more explicit arguments to your one method, or provide
multiple methods, for the purpose of instantiating the class.

For an example of the former approach, take a look at .NET's WebRequest
class, where you provide a URI and the framework creates an
HttpWebRequest, FtpWebRequest, etc. depending on the scheme of the URI.

I see.
Good to know I am going in the right direction :)

Thanks Pete,

regards,
Marcel
 

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