interface IShape
{
double[] Args { get; set; }
double GetArea();
double GetPerimeter();
void Print();
}
class Square : IShape
{
public double[] Args {
get; set; }
public Square(double s) =>
Args = new double[] { s };
public double
GetArea() => Math.Pow(Args[0], 2);
public double
GetPerimeter() => Args[0] * 4;
public void Print()
{
Console.Write($"I am a {this.GetType().Name}");
Console.WriteLine($"Area:{GetArea()}\tPerimeter:{GetPerimeter()}\r\n");
}
}
class Rectangle : IShape
{
public double[] Args {
get; set; }
public Rectangle(double width, double height) => Args = new double[] { width, height };
public double
GetArea() => Args[0] * Args[1];
public double
GetPerimeter() => Args[0] * 2 +
Args[1] * 2;
public void Print()
{
Console.WriteLine($"I am a {this.GetType().Name}");
Console.WriteLine($"Area:{GetArea()}\tPerimeter:{GetPerimeter()}\r\n");
}
}
class Triangle : IShape
{
public double[] Args {
get; set; }
public Triangle(double
adjacent, double theta, double hypotenuse)
=> Args = new double[] { adjacent, theta, hypotenuse };
public double
GetArea()
{
var adjacent = Args[0];
var theta = ToRadians(Args[1]);
var hypotenuse = Args[2];
var height = Math.Sin(theta) * hypotenuse;
return adjacent * height / 2;
}
public double
GetPerimeter()
{
var adjacent = Args[0];
var theta = ToRadians(Args[1]);
var hypotenuse = Args[2];
var height = Math.Sin(theta) * hypotenuse;
var alpha = ToRadians(180 - 90 - Args[1]);
var subBase = Math.Sin(alpha) * hypotenuse;
var diffBase = adjacent - subBase;
var opposite = Math.Sqrt(Math.Pow(height, 2) + Math.Pow(diffBase,
2));
return adjacent + hypotenuse + opposite;
}
}
class Program
{
static void Main(string[] args)
{
var data = new[,] { { new[] { 6.0 } }, { new[] { 3.0, 4.0 } }, { new[] { 5.0, 30.0, 7.0 } }, { new[] { 5.0, 3.0 } } };
foreach (var d in data)
if (d.Length == 1)
(new Square(d[0])).Print();
else if (d.Length ==
2)
(new Rectangle(d[0], d[1])).Print();
else if (d.Length ==
3)
(new Triangle(d[0], d[1], d[2])).Print();
}
}
For each data entry we have to check how many values it contains and then create a shape appropriately, now that's sloppy even in this contrived example, so let's define a factory to handle the creation of our shapes.
from our UML you can see that all of our shapes implement the IShape interface, then we have an interface that describes our factory, it defines one function that returns instances of our shapes then that interface is realized by our ShapeFactory which encapsulates our instantiation logic.
from our UML you can see that all of our shapes implement the IShape interface, then we have an interface that describes our factory, it defines one function that returns instances of our shapes then that interface is realized by our ShapeFactory which encapsulates our instantiation logic.
interface IShapeFactory
{
IShape CreateShape(double[] args);
}
Simple as that just one function that takes in our data and returns an instance of IShape; next let's create a concrete implementation of our factory
class ShapeFactory : IShapeFactory
{
public IShape CreateShape(double[] args)
{
if (args.Length == 1)
return new
Square(args[0]);
if (args.Length == 2)
return new
Rectangle(args[0], args[1]);
if (args.Length == 3)
return new
Triangle(args[0], args[1], args[2]);
return null;
}
}
now we've encapsulated our instantiation logic into a factory and now let's use our factory in our program
class Program
{
static void Main(string[] args)
{
var data = new[,] {
{ new[] { 6.0 } }, { new[] { 3.0, 4.0 } },
{ new[] { 5.0, 30.0, 7.0 } }, { new[] { 5.0, 3.0 } }
};
var shapeFactory = new ShapeFactory();
foreach (var d in data)
shapeFactory.CreateShape(d).Print();
}
}
and voila much cleaner code, now that our factory handles the instantiation of our shapes.