Derive Enum

H

hufaunder

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
 
D

DeveloperX

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,series1);

param.Add(series1);
param.Add(series2);
mySecondChart =
ChartFactory.CreateChart(ChartType.BandsChart,param);

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,pParameters.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;
}
}
}
}
 
H

hufaunder

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?

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,series1);

param.Add(series1);
param.Add(series2);
mySecondChart =
ChartFactory.CreateChart(ChartType.BandsChart,param);

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,pParameters.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;
}
}
}



}- Hide quoted text -

- Show quoted text -- Hide quoted text -

- Show quoted text -

Wow, thanks a lot for that reply.That leaves me with just one
question. What is a factory useful here? When you create a chart you
actually have to know what arguments (one or two) you have to supply.
If I already have that information I could the ctor of the appropriate
function directly. I'm sure there is a good reason. It's just that I
am not too familiar with that concept. Thanks again for the answer.
 
D

DeveloperX

Wow, thanks a lot for that reply.That leaves me with just one
question. What is a factory useful here? When you create a chart you
actually have to know what arguments (one or two) you have to supply.
If I already have that information I could the ctor of the appropriate
function directly. I'm sure there is a good reason. It's just that I
am not too familiar with that concept. Thanks again for the answer.

It's just one approach really. As we're interested in getting an
IChart out, as opposed to a LineChart or a BarChart specifically, it
seemed sensible to create a factory which will validate your request
and return the appropriate IChart or raise the appropriate error.

One of the key points of using an interface is that you're saying "I
have a number of different classes, all of which should function in a
specific way". This means your code that uses the Chart library should
expect each chart to be able to draw itself for example. If you do
something like:

IChart myChart = new BarChart(...);

you're committing to using a BarChart in that bit of code. If you need
it to be configurable your applications will end up with methods that
return IChart references and do effectively what the Factory does. The
factory way means we're keeping everything in the same place which
makes it maintainable. As there's only one place that creates charts,
if you update that one place, all the applications that use the charts
will be updated.

I hope that made some sense :)
 

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

Similar Threads


Top