Reputation: 1988
I have various classes which generate excel graphs.
Each class generates a different graph.
They all share the same private variables, with different values.
I wish to write a generic code, in order to prevent "if" statements to determine which graph is it.
Here is an example of one of the classes:
using System;
namespace GraphsGenerator
{
public class GraphOne
{
#region Private Members
private string m_baseDir = "";
private static string m_graphName = "GraphOne";
private string m_imageFile = m_graphName + Utils.ImageExtension;
#endregion Private Members
#region Properties
public string BaseDir
{
set { m_baseDir = value; }
}
public string GraphName
{
get { return m_graphName; }
}
public string ImageFile
{
get { return m_imageFile; }
set { m_imageFile = value; }
}
#endregion Properties
#region Constructor
public HandTrackingGraphs(string baseDir)
{
m_baseDir = baseDir;
}
#endregion Constructor
}
}
I tried to do this in my main:
List<object> listOfGraphs = new List<object>();
listOfGraphs.Add(new GraphOne());
listOfGraphs.Add(new GraphTwo());
listOfGraphs.Add(new GraphThree());
foreach (object currentGraph in listOfGraphs)
{
string imageFile = currentGraph.ImageFile;
}
But of course this cannot be done.
Any ideas?
Upvotes: 2
Views: 308
Reputation: 3626
In this case all you need is to implement Strategy Pattern To get some idea see this code
abstract class AbsGraph
{
public string ImageFile { get; protected set; }
//other properties
public abstract void DrawGraph();
//other methods
public void CommonMethod()
{ }
//other common method
}
class Graph1 : AbsGraph
{
public override void DrawGraph()
{
//do graph specific task
}
}
class Graph2 : AbsGraph
{
public override void DrawGraph()
{
//do graph specific task
}
}
class Graph3 : AbsGraph
{
public override void DrawGraph()
{
//do graph specific task
}
}
Now you can do
var absGraphs = new List<AbsGraph>
{
new Graph1(),
new Graph2(),
new Graph3()
};
foreach (var graph in absGraphs)
{
graph.DrawGraph();
}
Upvotes: 0
Reputation: 82136
Interfaces have already been suggested, so to give you another alternative - you could use a base class because you not only share common properties/methods but you also share common implementation e.g.
public abstract class Graph
{
#region Private Members
private string m_baseDir = "";
private string m_imageFile = m_graphName + Utils.ImageExtension;
#endregion Private Members
#region Properties
public string BaseDir
{
set { m_baseDir = value; }
}
public string GraphName
{
get { return m_graphName; }
}
public abstract string ImageFile { get; }
#endregion Properties
#region Constructor
public HandTrackingGraphs(string baseDir)
{
m_baseDir = baseDir;
}
#endregion Constructor
}
public class GraphOne : Graph
{
public override string ImageFile { get { return "GraphOne"; } }
}
public class GraphTwo : Graph
{
public override string ImageFile { get { return "GraphTwo"; } }
}
public class GraphThree : Graph
{
public override string ImageFile { get { return "GraphThree"; } }
}
Then your usage becomes
List<Graph> listOfGraphs = new List<Graph>();
listOfGraphs.Add(new GraphOne());
listOfGraphs.Add(new GraphTwo());
listOfGraphs.Add(new GraphThree());
foreach (IGraph currentGraph in listOfGraphs)
{
string imageFile = currentGraph.ImageFile;
}
Upvotes: 1
Reputation: 151720
But of course this cannot be done.
It can, using interfaces. Define an interface containing the method you want to run:
public interface IGraphWithImageFile
{
string ImageFile { get; }
}
Then apply the interface to all classes, and declare the list as List<IGraphWithImageFile>
.
Upvotes: 4
Reputation: 14682
Make all the classes inherit from a common GraphBase abstract class. Put your common properties as abstract on this class, then override them in the derived classes.
Upvotes: 2
Reputation: 1503519
They all share the same private variables, with different values.
They should all implement the same interface, which exposes the ImageFile
property. For example:
public interface IGraph
{
// TODO: Consider making this read-only in the interface...
public string ImageFile { get; set; }
}
Then you can have:
List<IGraph> listOfGraphs = new List<IGraph>();
listOfGraphs.Add(new GraphOne());
listOfGraphs.Add(new GraphTwo());
listOfGraphs.Add(new GraphThree());
foreach (IGraph currentGraph in listOfGraphs)
{
string imageFile = currentGraph.ImageFile;
}
You could use an abstract base class instead of an interface, too. That's a bit more restrictive, but it means graphs could share common implementation too.
(You could even create an interface implemented by an abstract base class, if you really wanted the flexibility but also code reuse.)
Upvotes: 8