class design quandary

B

Baris

Given the C# code below, can anyone think of a better class design? What
really gets my goat is that the code within derived classes D1 and D2 is
identical and in my mind should be refactored into a base class, but how
can I move this particular 'shared functionality' into a base class?

If anyone can suggest a better newsgroup for this, such as one focussed
primarily on C# class design, please let me know.

[This could be easily done with an intermediate template class in the
hierarchy in C++, I think.]

// quandary.cs
// compile with csc.exe quandary.cs
class app
{
public static void Main()
{
D1 d1 = new D1();
D2 d2 = new D2();

D1.SetFoo("something marvellous, specific to class D1");
D2.SetFoo("something wonderful , specific to class D2");

System.Console.WriteLine(d1.GetFoo());
System.Console.WriteLine(d2.GetFoo());
}
}

abstract class Base
{
public abstract string GetFoo();
}

class D1 : Base
{
private static string _foo;
public static void SetFoo(string s)
{
_foo = s;
}
public override string GetFoo()
{
return _foo;
}
}

class D2 : Base
{
private static string _foo;
public static void SetFoo(string s)
{
_foo = s;
}
public override string GetFoo()
{
return _foo;
}
}
// quandary.cs ends
 
F

Frank Oquendo

Baris said:
Given the C# code below, can anyone think of a better class design?
What really gets my goat is that the code within derived classes D1
and D2 is identical and in my mind should be refactored into a base
class, but how can I move this particular 'shared functionality' into
a base class?

It would seem the *only* thing you have is a base class as your example
shows no reason to have either derived class. What exactly are you
after?

--
There are 10 kinds of people. Those who understand binary and those who
don't.

http://code.acadx.com
(Pull the pin to reply)
 
B

Baris

It would seem the *only* thing you have is a base class as your example
shows no reason to have either derived class. What exactly are you
after?

Conceptually, I want to associate data/functionality with a given class
at runtime, that can be returned from a virtual method on a base class.

IRL, these classes are derived from a class that derives from TreeNode,
and the static members represent class-specific context menus; for a
node of a given type I want a particular context menu. At runtime, I set
the menus for each class.

Does that help?

Baris
 
B

Baris

Frank said:
It would seem the *only* thing you have is a base class as your example
shows no reason to have either derived class. What exactly are you
after?

BTW, I disagree with this statement; I wouldn't get the same
functionality with only one class. These statements from the Main()
wouldn't print different values for these two lines if d1 and d2 were
instances of the same class:

System.Console.WriteLine(d1.GetFoo());
System.Console.WriteLine(d2.GetFoo());

Baris.
 
D

Doug Forster

Hi Baris,

You might be able to do something along the lines you want via reflection.
Heres an example of a line of code from one of our base classes that
'reaches' upwards in the class hierachy:

string strTableName = (string)GetType().InvokeMember ("TableName",
BindingFlags.Public | BindingFlags.GetProperty | BindingFlags.Static, null,
null, new object [] {});

Cheers

Doug Forster
 
A

Anthony Borla

Baris said:
Conceptually, I want to associate data/functionality with
a given class at runtime, that can be returned from a virtual
method on a base class.

IRL, these classes are derived from a class that derives from
TreeNode, and the static members represent class-specific
context menus; for a node of a given type I want a particular
context menu. At runtime, I set the menus for each class.

The following [essentially an implementation of an abstract 'Menu' factory]
is probably overkill for your needs, but:

* It ensures that most of the functionality resides in the
base class

* Does not rely on any language-specific facility e.g.
reflection [though could easily be altered to do so]

* May easily be expanded to have the menu setup code reside
in a method rather than in the derived class constructors
as is currently the case

I hope this helps.

Anthony Borla

// ----------------- Code Sample Start --------------------
using System;
using System.Collections;

class Application
{
public static void Main()
{
Menu m;

m = new D1().GetMenu();
Console.WriteLine(m);

m = new D2().GetMenu();
Console.WriteLine(m);

m = new D3().GetMenu();
Console.WriteLine(m);
}
}

class Menu
{
public Menu(String name)
{
this.name = name;
}

public override String ToString()
{
return name;
}

private String name;
}

abstract class Base
{
abstract public Menu GetMenu();

protected static Menu GetMenu(String name)
{
return (Menu) menuTable[name];
}

protected static Boolean RegisterMenu(String name, Menu menu)
{
menuTable.Add(name, menu);
return menuTable.ContainsKey(name);
}

protected static void DropMenu(String name)
{
menuTable.Remove(name);
}

private static Hashtable menuTable = new Hashtable();
}

class D1 : Base
{
public D1()
{
if (!registered)
{
Menu menu = new Menu(menuName);

// Customise menu ...

registered = RegisterMenu(menuName, menu);
}
}

public override Menu GetMenu()
{
return GetMenu(menuName);
}

private static Boolean registered = false;
private static String menuName = "D1";
}

class D2 : Base
{
public D2()
{
if (!registered)
{
Menu menu = new Menu(menuName);

// Customise menu ...

registered = RegisterMenu(menuName, menu);
}
}

public override Menu GetMenu()
{
return GetMenu(menuName);
}

private static Boolean registered = false;
private static String menuName = "D2";
}

class D3 : Base
{
public D3()
{
if (!registered)
{
Menu menu = new Menu(menuName);

// Customise menu ...

registered = RegisterMenu(menuName, menu);
}
}

public override Menu GetMenu()
{
return GetMenu(menuName);
}

private static Boolean registered = false;
private static String menuName = "D3";
}
 
S

Shon Katzenberger

Hi Baris,

You may want to experiment with something like the following. The idea is
that Base has a protected nested class Data and a protected abstract
method/property to get the data from an instance. Each derived class has a
static field of type Data and implements the GetData method to return the
value of its field.

Derived classes also need to either supply stub methods that just delegate
to Base/Data or alternatively, Data can implement some interface IFoo and
each derived class has a static GetIFoo method/property.

// This is really only needed if you decide NOT to have stub methods for
every bit of functionality.
interface IFoo
{
void SetFoo(string s);
public string GetFoo();
}

abstract class Base
{
protected class Data : IFoo
{
public string _foo;

// The methods are only needed if you use the IFoo interface.
public void SetFoo(string s) { _foo = s; }
public string GetFoo() { return _foo; }
}

// Derived classes are required to provide us with their data.

protected abstract Data GetData();

// Base can now fully implement the instance methods (except for the
call to GetData() of course).
public string GetFoo() { return GetData()._foo; }
public void SetFoo(string s) { GetData()._foo = s; } // optional. Can
also use D1.SetFoo(...)
}

class D1 : Base
{
private static Data data = new Data();

// So Base can get our data.
protected override Data GetData() { return data; }

// You can have a static GetIFoo so clients can call
GetIFoo().SetFoo("Hello").
// This helps if there are lots of methods on the IFoo interface.
public static IFoo GetIFoo() { return data; }

// Or have stub methods. Or have both a static GetIFoo plus stub methods
for the most commonly used methods.
public static void SetFoo(string s)
{
data.SetFoo(s);
}
}

class D2 : Base
{

private static Data data = new Data();

// So Base can get our data.
protected override Data GetData() { return data; }

// D2 might have a different set of stub methods than D1 if so desired.
public static IFoo GetIFoo() { return data; }
}

Hope this helps.

Shon Katzenberger

Baris said:
Given the C# code below, can anyone think of a better class design? What
really gets my goat is that the code within derived classes D1 and D2 is
identical and in my mind should be refactored into a base class, but how
can I move this particular 'shared functionality' into a base class?

If anyone can suggest a better newsgroup for this, such as one focussed
primarily on C# class design, please let me know.

[This could be easily done with an intermediate template class in the
hierarchy in C++, I think.]

// quandary.cs
// compile with csc.exe quandary.cs
class app
{
public static void Main()
{
D1 d1 = new D1();
D2 d2 = new D2();

D1.SetFoo("something marvellous, specific to class D1");
D2.SetFoo("something wonderful , specific to class D2");

System.Console.WriteLine(d1.GetFoo());
System.Console.WriteLine(d2.GetFoo());
}
}

abstract class Base
{
public abstract string GetFoo();
}

class D1 : Base
{
private static string _foo;
public static void SetFoo(string s)
{
_foo = s;
}
public override string GetFoo()
{
return _foo;
}
}

class D2 : Base
{
private static string _foo;
public static void SetFoo(string s)
{
_foo = s;
}
public override string GetFoo()
{
return _foo;
}
}
// quandary.cs ends
 

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