On 18 Apr, 07:07, "hufaun...@yahoo.com" <hufaun...@yahoo.comwrote:
Imagine you have a charting library that can draw lines, bars,
floating bars, bands, etc.
Lines and bars need only one input. Floating bars and bands need two
inputs. There are two approaches:
1) One enum with all 4 types (bars, band, etc). One chart class that
accepts up to 2 arrays of values. If the user choses a band but there
is only one input array throw an exception. If the user passes two
input arrays with different lengths throw an exception.
2) One enum with all 4 types. A class that accepts one array. Another
class that accepts two arrays or alternatively pair of values. We
still have to throw an exception if the "one array class" is chosen
but a band type is selected.
3) An enum for 1-input-charts (line,bar) and one for 2-input-charts. A
class that accepts only one input and one that accepts only two
inputs. The later class uses the later enum.
What approach is the best? If it's 3 then I would need something like
this:
interface IChart
{
ChartType Type { get; }
}
The problem is that ChartType is an enum and one cannot derive from
enums. How would that be solved?
Thanks
I don't understand your last statement, why would you want to try and
derive from an enum?
I'd stick with one enum if you plan to have both types of charts
implement an interface.
I've attached a little example. It's not necessarily exactly what you
want but shows a few examples of different ways of doing it. In a
nutshell there's an interface for all chart types which just exposes
type and a draw method, then two types of chart one that needs two
sets of parameters and one that works with only one. These are created
by a factory class that has variously overloaded CreateChart methods.
Some of the bits are a redundant, I've just added them to show
different approaches, for example the parameter class has a validate
method, but the same validation is repeated in the factory.
There are plenty of other ways of doing it, you could have a base
Chart object that handles the basics and then derive specialised
charts from there for example.
Paste it over a new console app and it should run. If not, check for
line breaks.
using System;
namespace ConsoleApplication9
{
class Class1
{
[STAThread]
static void Main(string[] args)
{
IChart myFirstChart;
IChart mySecondChart;
IChart myThirdChart;
int[] series1 = new int[]{1,2,3,4,5,6,7,8,9,10};
int[] series2 = new int[]{11,12,13,14,15,16,17,18,19,20};
System.Collections.ArrayList param = new
System.Collections.ArrayList();
myFirstChart =
ChartFactory.CreateChart(ChartType.LineChart,serie s1);
param.Add(series1);
param.Add(series2);
mySecondChart =
ChartFactory.CreateChart(ChartType.BandsChart,para m);
ChartParameters paramObj = new ChartParameters(ChartType.BarChart,
series2, null);
myThirdChart = ChartFactory.CreateChart(paramObj);
myFirstChart.Draw();
mySecondChart.Draw();
myThirdChart.Draw();
Console.Read();
}
}
public enum ChartType
{
LineChart,
BarChart,
FloatingBarChart,
BandsChart
}
public interface IChart
{
ChartType TypeOfChart
{
get;
}
void Draw();
}
public class ChartFactory
{
public static IChart CreateChart(ChartType pType, params object[]
pParams)
{
//Comically this one will never be used because of
//public static IChart CreateChart(ChartType pType, int[] pSeries1,
int[] pSeries2) below
switch(pParams.Length)
{
case 1:
ChartFactory.CreateChart(pType,(int[])pParams[0]);
break;
case 2:
ChartFactory.CreateChart(pType,(int[])pParams[0],pParams[1]);
break;
default:
throw new Exception("Eeep!");
}
return null;
}
public static IChart CreateChart(ChartType pType,
System.Collections.ArrayList pData)
{
return ChartFactory.CreateChart(pType, (int[])pData[0],
(pData.Count==2 ? (int[])pData[1] : null));
}
public static IChart CreateChart(ChartType pType, int[] pSeries)
{
return ChartFactory.CreateChart(pType, pSeries, null);
}
public static IChart CreateChart(ChartParameters pParameters)
{
pParameters.Validate();
return
ChartFactory.CreateChart(pParameters.TypeOfChart,p Parameters.Series1,
pParameters.Series2);
}
public static IChart CreateChart(ChartType pType, int[] pSeries1,
int[] pSeries2)
{
switch(pType)
{
case ChartType.LineChart:
case ChartType.BarChart:
if (pSeries2 == null)
{
return new SingleArrayChart(pType, pSeries1);
}
else
{
throw new Exception("Expected one set of data");
}
case ChartType.FloatingBarChart:
case ChartType.BandsChart:
if (pSeries2 == null)
{
throw new Exception("Expected two sets of data");
}
else
{
return new DoubleArrayChart(pType, pSeries1, pSeries2);
}
default:
return null;
}
}
}
public class SingleArrayChart : IChart
{
private ChartType _chartType;
private int[] _data;
public SingleArrayChart(ChartType pType, int[] pData)
{
_chartType = pType;
_data = pData;
}
public ChartType TypeOfChart
{
get
{
return _chartType;
}
}
public void Draw()
{
Console.WriteLine("I am drawing a {0}",_chartType.ToString());
}
}
public class DoubleArrayChart : IChart
{
private ChartType _chartType;
private int[] _data1;
private int[] _data2;
public DoubleArrayChart(ChartType pType, int[] pData1, int[] pData2)
{
_chartType = pType;
_data1 = pData1;
_data2 = pData2;
if(_data1.Length != _data2.Length)
{
throw new Exception("Data arrays have differents lengths");
}
}
public ChartType TypeOfChart
{
get
{
return _chartType;
}
}
public void Draw()
{
Console.WriteLine("I am drawing a {0}",_chartType.ToString());
}
}
public class ChartParameters
{
// should all be properties
public int[] Series1;
public int[] Series2;
public ChartType TypeOfChart;
public ChartParameters(ChartType pType, int[] pSeries1, int[]
pSeries2)
{
Series1 = pSeries1;
Series2 = pSeries2;
TypeOfChart = pType;
}
public void Validate()
{
switch(TypeOfChart)
{
case ChartType.BarChart:
case ChartType.LineChart:
if (Series2 != null || Series1 == null)
{
throw new Exception("Expected one set of data");
}
break;
case ChartType.FloatingBarChart:
case ChartType.BandsChart:
if(Series2 == null || Series1 == null)
{
throw new Exception("Expected two sets of data");
}
if(Series2.Length != Series1.Length)
{
throw new Exception("Series data should be same length");
}
break;
}
}
}
}