How to design this?

G

Guest

I have a rather newbie question regarding design of class hierarchy.
Suppose I have a class Class0, and need to implement a public
Class0.compute() interface. There are three different ways to choose
the implementation, and the user of the class has to be able to make
that choice. Here is what I have in mind. I declare three classes,
ClassA, ClassB, ClassC, and each of them has a distinct compute()
method that can be used by Class0. Class0 is a template class, as
follows:

template <class T>
class Class0 {
public:
double compute() { return p->compute(); }
private:
T *p;
};

Then I could do:

Class0<ClassA> C;
C.compute();

Problem: classA.compute(), classB.compute() and classC.compute() all
have different number and types of parameters. I might also want to
add classD, etc. in the future. This means I would need to implement
three different compute() functions in the public area of Class0.

Alternatively, I could write a method in Class0 that returns a
corresponding compute() function from the pointer p, but this doesn't
seem elegant.

Another idea I have is to declare Class0 a descendant of Class{A,B,C}:

template<class T>
class Class0 : public T {
....
}
and then

Class0<classA> C;

Then Class0 will inherit compute() from classes ClassA, etc.
What makes me uncomfortable is that Class0 and classes Class{A,B,C}
do not really have "is-a" relationship. A,B,C only provide the means
to do certain computations.

Any better way to accomplish what I am trying to do?

Many thanks,
 
H

Howard

I have a rather newbie question regarding design of class hierarchy.
Suppose I have a class Class0, and need to implement a public
Class0.compute() interface. There are three different ways to choose
the implementation, and the user of the class has to be able to make
that choice. Here is what I have in mind. I declare three classes,
ClassA, ClassB, ClassC, and each of them has a distinct compute()
method that can be used by Class0. Class0 is a template class, as
follows:

template <class T>
class Class0 {
public:
double compute() { return p->compute(); }
private:
T *p;
};

Then I could do:

Class0<ClassA> C;
C.compute();

Problem: classA.compute(), classB.compute() and classC.compute() all
have different number and types of parameters. I might also want to
add classD, etc. in the future. This means I would need to implement
three different compute() functions in the public area of Class0.

Alternatively, I could write a method in Class0 that returns a
corresponding compute() function from the pointer p, but this doesn't
seem elegant.

Another idea I have is to declare Class0 a descendant of Class{A,B,C}:

template<class T>
class Class0 : public T {
...
}
and then

Class0<classA> C;

Then Class0 will inherit compute() from classes ClassA, etc.
What makes me uncomfortable is that Class0 and classes Class{A,B,C}
do not really have "is-a" relationship. A,B,C only provide the means
to do certain computations.

Any better way to accomplish what I am trying to do?

Many thanks,

If the three versions have different number and types of parameters, then I
don't see any reason to have distinct classes at all. Why not just have
three different compute() functions? Something like:

public:
double compute( );
double compute( double param1 );
double compute( double param1, int param2 );

Will something like this work?

-Howard
 
V

Victor Bazarov

I have a rather newbie question regarding design of class hierarchy.
Suppose I have a class Class0, and need to implement a public
Class0.compute() interface. There are three different ways to choose

Only three?..
the implementation, and the user of the class has to be able to make
that choice. Here is what I have in mind. I declare three classes,
ClassA, ClassB, ClassC, and each of them has a distinct compute()
method that can be used by Class0. Class0 is a template class,

You mean, Class0 is a _class_template_?
as
follows:

template <class T>
class Class0 {
public:
double compute() { return p->compute(); }
private:
T *p;
};

Then I could do:

Class0<ClassA> C;
C.compute();

Problem: classA.compute(), classB.compute() and classC.compute() all
have different number and types of parameters. I might also want to
add classD, etc. in the future. This means I would need to implement
three different compute() functions in the public area of Class0.

Alternatively, I could write a method in Class0 that returns a
corresponding compute() function from the pointer p, but this doesn't
seem elegant.

_A_ method? I think you actually will need to write as many methods
as there will be classes used to instantiate Class0. You can do it
implicitly by introducing a member _template_

template<class T> class Class0 {
...
template<class U> U get_compute() { return &T::compute; }

somehow (not sure this is going to work, though, how would U be deduced?)
Another idea I have is to declare Class0 a descendant of Class{A,B,C}:

template<class T>
class Class0 : public T {
...
}
and then

Class0<classA> C;

Then Class0 will inherit compute() from classes ClassA, etc.
What makes me uncomfortable is that Class0 and classes Class{A,B,C}
do not really have "is-a" relationship.

Huh? First of all, you shouldn't call 'Class0' a _class_ because it is
not a class. It's a template. Second, Class0<ClassA> _class_ does have
the "is-a" relationship with ClassA because it is publicly inherited
A,B,C only provide the means
to do certain computations.

Any better way to accomplish what I am trying to do?

I'd probably vote for the third way.

V
 
G

Guest

Victor Bazarov said:
Only three?..

There could be more.
You mean, Class0 is a _class_template_?
right.


_A_ method? I think you actually will need to write as many methods
as there will be classes used to instantiate Class0. You can do it
implicitly by introducing a member _template_

template<class T> class Class0 {
...
template<class U> U get_compute() { return &T::compute; }

somehow (not sure this is going to work, though, how would U be deduced?)


Huh? First of all, you shouldn't call 'Class0' a _class_ because it is
not a class. It's a template. Second, Class0<ClassA> _class_ does have
the "is-a" relationship with ClassA because it is publicly inherited
from it. And so does Class0<ClassB> with ClassB, and Class0<ClassC> with
ClassC, respectively.


Forgive my language. Class0<ClassA> does of course have the "is-a"
relationship the way the declarations are written. What I meant to
say was that _logically_ I don't feel comfortable deriving
Class0<ClassA> from ClassA, since ClassA only provides the
implementation of a compute() function for Class0<ClassA>.
 
G

Guest

Howard said:
If the three versions have different number and types of parameters, then I
don't see any reason to have distinct classes at all. Why not just have
three different compute() functions? Something like:

public:
double compute( );
double compute( double param1 );
double compute( double param1, int param2 );

Will something like this work?

It will, but I was trying to avoid adding even more compute()
functions in case I have classes ClassD, ClassE, etc. in the future.
 
V

Victor Bazarov

[..] Class0<ClassA> does of course have the "is-a"
relationship the way the declarations are written. What I meant to
say was that _logically_ I don't feel comfortable deriving
Class0<ClassA> from ClassA, since ClassA only provides the
implementation of a compute() function for Class0<ClassA>.

Ah, yes. You feel that from the OOD standpoint, such derivation is
unjustified, maybe? Don't. It's justified because it solves your
problem, and has no adverse side effects (or does it?).

You should ask yourself, "how am I going to use the 'compute' function?"
To be entirely honest, since you didn't post any code to illustrate the
use of 'Class0', there was no ground to dismiss any of your solutions.
You asked about the design in vacuum. Whatever works, should work there.
As soon as you realise that you need to store Class0<> objects in some
container, for example, you will immediately see the drawbacks of the
template class...

V
 
G

Guest

Victor Bazarov said:
[..] Class0<ClassA> does of course have the "is-a"
relationship the way the declarations are written. What I meant to
say was that _logically_ I don't feel comfortable deriving
Class0<ClassA> from ClassA, since ClassA only provides the
implementation of a compute() function for Class0<ClassA>.

Ah, yes. You feel that from the OOD standpoint, such derivation is
unjustified, maybe? Don't. It's justified because it solves your
problem, and has no adverse side effects (or does it?).

You should ask yourself, "how am I going to use the 'compute' function?"
To be entirely honest, since you didn't post any code to illustrate the
use of 'Class0', there was no ground to dismiss any of your solutions.
You asked about the design in vacuum. Whatever works, should work there.
As soon as you realise that you need to store Class0<> objects in some
container, for example, you will immediately see the drawbacks of the
template class...

Thanks, appreciate it.
 
K

Karthik Kumar

I have a rather newbie question regarding design of class hierarchy.
Suppose I have a class Class0, and need to implement a public
Class0.compute() interface. There are three different ways to choose
the implementation, and the user of the class has to be able to make
that choice. Here is what I have in mind. I declare three classes,
ClassA, ClassB, ClassC, and each of them has a distinct compute()
method that can be used by Class0. Class0 is a template class, as
follows:

template <class T>
class Class0 {
public:
double compute() { return p->compute(); }
private:
T *p;
};

Then I could do:

Class0<ClassA> C;
C.compute();

Problem: classA.compute(), classB.compute() and classC.compute() all
have different number and types of parameters. I might also want to
add classD, etc. in the future. This means I would need to implement
three different compute() functions in the public area of Class0.

Alternatively, I could write a method in Class0 that returns a
corresponding compute() function from the pointer p, but this doesn't
seem elegant.

Another idea I have is to declare Class0 a descendant of Class{A,B,C}:

template<class T>
class Class0 : public T {
...
}
and then

Class0<classA> C;

Then Class0 will inherit compute() from classes ClassA, etc.
What makes me uncomfortable is that Class0 and classes Class{A,B,C}
do not really have "is-a" relationship. A,B,C only provide the means
to do certain computations.


If you are looking for a is-a relationship , how about
public inheritance ?

class Class0 {

public:
virtual double compute() = 0;

};

And then,

class ClassA : public Class0 {

public:
double compute() {
// your implementation here ..
}
};



All three classes would have a is-a relationship with Class0 .
...


btw - I guess this is more on-topic for news://comp.object
or -
http://groups-beta.google.com/group/comp.object .
 
T

Tom Widmer

I have a rather newbie question regarding design of class hierarchy.
Suppose I have a class Class0, and need to implement a public
Class0.compute() interface. There are three different ways to choose
the implementation, and the user of the class has to be able to make
that choice. Here is what I have in mind. I declare three classes,
ClassA, ClassB, ClassC, and each of them has a distinct compute()
method that can be used by Class0. Class0 is a template class, as
follows:

template <class T>
class Class0 {
public:
double compute() { return p->compute(); }
private:
T *p;
};

Then I could do:

Class0<ClassA> C;
C.compute();

Problem: classA.compute(), classB.compute() and classC.compute() all
have different number and types of parameters. I might also want to
add classD, etc. in the future. This means I would need to implement
three different compute() functions in the public area of Class0.

Alternatively, I could write a method in Class0 that returns a
corresponding compute() function from the pointer p, but this doesn't
seem elegant.

How about the far simpler:

template <class T>
class Template0
{
T* p;
public:
T& getComputer() const
{
return *p;
}
};

C.getComputer().compute(...);
?
Another idea I have is to declare Class0 a descendant of Class{A,B,C}:

template<class T>
class Class0 : public T {
...
}
and then

Class0<classA> C;

Then Class0 will inherit compute() from classes ClassA, etc.
What makes me uncomfortable is that Class0 and classes Class{A,B,C}
do not really have "is-a" relationship. A,B,C only provide the means
to do certain computations.

Any better way to accomplish what I am trying to do?

Without knowing the purpose Class0 is meant to hold, it's hard to
offer much advice. But public inheritence is a common approach in
policy-based design where it is considered "interface inheritence"
rather than an is-a relationship. Are you doing policy-based design?

Tom
 
A

andre dajd

I have a rather newbie question regarding design of class hierarchy.
Suppose I have a class Class0, and need to implement a public
Class0.compute() interface. There are three different ways to choose
the implementation, and the user of the class has to be able to make
that choice. Here is what I have in mind. I declare three classes,
ClassA, ClassB, ClassC, and each of them has a distinct compute()
method that can be used by Class0. Class0 is a template class, as
follows:

template <class T>
class Class0 {
public:
double compute() { return p->compute(); }
private:
T *p;
};

Then I could do:

Class0<ClassA> C;
C.compute();

Problem: classA.compute(), classB.compute() and classC.compute() all
have different number and types of parameters. I might also want to
add classD, etc. in the future. This means I would need to implement
three different compute() functions in the public area of Class0.

Alternatively, I could write a method in Class0 that returns a
corresponding compute() function from the pointer p, but this doesn't
seem elegant.

Yes, the last one is a bad idea.

It sounds like the biggest issue is that different computes may have
different signatures. The standard way to handle this in C++ fashion is to
make the whole signature a new statically or dynamically polymorpohic object
and then use a flavour of repeated dispatch.

Here is one, purely dynamic way to do that, sort of "Adapter" pattern.

// base class for all argument types.
struct Arg
{
virtual
~Arg() {}

virtual bool
isValid() const =0;
};

// base class for compute
struct Class0
{
virtual
~Class0() {}

virtual void
compute(Arg cosnt&) = 0;
};

// example pair

struct ArgA
: public Arg
{
int nonNegativeNumber;

bool
isValid() { return nonNegativeNumber >=0; }
};

struct ClassA
: public Class0
{
void
compute(Arg const& arg)
{
try
{
ArgA const&r = dynamic_cast<ArgA const&>(arg);
if(!r.isValid())
throw "Invalid argumet";

// do something material
}
catch(bad_cast)
{
throw "Bad argument type";
}
}
};


The main goal you achieve here is keeping the root totally polymorphic, no
templates, however, obvious code replication in implementation of "compute".

Another extreme is fully static design. No runtime checks

struct IComputer
{
virtual
~IComputer() {}

virtual void
compute() = 0;
};

template<typename _Computer>
struct Class0
: public IComputer
{
typedef _Computer ComputerT;
typedef typename ComputerT::ArgT ArgT;

void
setArg(ArgT const& arg) { mt_pComputer->setArg(arg); }

void
compute() { m_pComputer->compute(); }

protected:
ComputerT* m_pComputer;
};

Above example assumes that class provided as the template parameter will
have the typedef for ArgT.

You can have a mixture of the two, by introducing reflective dependence of
Arg on the Computer. Some "gurus" call this sort of pattern "Acyclic
visitor".

struct IArg
{
virtual
~IArg() {}

virtual bool
isValid() const =0;
};

template<typename _Computer>
struct Arg
: public IArg
{
typedef _Computer ComputerT;
};

template<typename _Computer>
struct Class0
{
typedef _Computer ComputerT;

void
setArg(ArgT const& arg) { mt_pComputer->setArg(arg); }

void
compute(IArg const& arg)
{
try
{
Arg<ComputerT> const& rArg = dynamic_cast<Arg<ComputerT>
const&>(arg);
if(!rArg.isValid())
throw "Invalid argument";
m_pComputer->compute(rArg);
}
catch(bad_cast)
{
throw "Bad argument type";
}
}

protected:
ComputerT* m_pComputer;
};

Note that the very first example will work even in Java. The latter is very
C++ specific though.

Rgds
d
 
G

Guest

andre dajd said:
Yes, the last one is a bad idea.

It sounds like the biggest issue is that different computes may have
different signatures. The standard way to handle this in C++ fashion is to
make the whole signature a new statically or dynamically polymorpohic object
and then use a flavour of repeated dispatch.

Here is one, purely dynamic way to do that, sort of "Adapter" pattern.

// base class for all argument types.
struct Arg
{
virtual
~Arg() {}

virtual bool
isValid() const =0;
};

// base class for compute
struct Class0
{
virtual
~Class0() {}

virtual void
compute(Arg cosnt&) = 0;
};

// example pair

struct ArgA
: public Arg
{
int nonNegativeNumber;

bool
isValid() { return nonNegativeNumber >=0; }
};

struct ClassA
: public Class0
{
void
compute(Arg const& arg)
{
try
{
ArgA const&r = dynamic_cast<ArgA const&>(arg);
if(!r.isValid())
throw "Invalid argumet";

// do something material
}
catch(bad_cast)
{
throw "Bad argument type";
}
}
};


The main goal you achieve here is keeping the root totally polymorphic, no
templates, however, obvious code replication in implementation of "compute".

Another extreme is fully static design. No runtime checks

struct IComputer
{
virtual
~IComputer() {}

virtual void
compute() = 0;
};

template<typename _Computer>
struct Class0
: public IComputer
{
typedef _Computer ComputerT;
typedef typename ComputerT::ArgT ArgT;

void
setArg(ArgT const& arg) { mt_pComputer->setArg(arg); }

void
compute() { m_pComputer->compute(); }

protected:
ComputerT* m_pComputer;
};

Above example assumes that class provided as the template parameter will
have the typedef for ArgT.

You can have a mixture of the two, by introducing reflective dependence of
Arg on the Computer. Some "gurus" call this sort of pattern "Acyclic
visitor".

struct IArg
{
virtual
~IArg() {}

virtual bool
isValid() const =0;
};

template<typename _Computer>
struct Arg
: public IArg
{
typedef _Computer ComputerT;
};

template<typename _Computer>
struct Class0
{
typedef _Computer ComputerT;

void
setArg(ArgT const& arg) { mt_pComputer->setArg(arg); }

void
compute(IArg const& arg)
{
try
{
Arg<ComputerT> const& rArg = dynamic_cast<Arg<ComputerT>
const&>(arg);
if(!rArg.isValid())
throw "Invalid argument";
m_pComputer->compute(rArg);
}
catch(bad_cast)
{
throw "Bad argument type";
}
}

protected:
ComputerT* m_pComputer;
};

Note that the very first example will work even in Java. The latter is very
C++ specific though.

Rgds
d

Thank you very much for such a detailed answer.
 
A

ARatio

Hi Vladimir:

I do not understand why you want to create several classes having several
compute() methods with distinct number of parameters.

Maybe you could build a base class like this:

class ComputableArgument
{

};


and to create ComputableArgumentA, ComputableArgumentB and
ComputableArgumentC subclasses.
In this way, you could define your compute method as follows:

class Class0
{
public:
compute(ComputableArgument aArguments);
};

and you could override your compute method getting your needed arguments
from the ComputableArgument class (downcasting). So, calling to this method
can be:

classB.compute(ComputableArgumentB(1,2,3));


I do not know if this solution can be useful, but voici :)

saludos


Ernesto
 

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

Members online

Forum statistics

Threads
473,981
Messages
2,570,188
Members
46,731
Latest member
MarcyGipso

Latest Threads

Top