Click here to Skip to main content
15,879,095 members
Please Sign up or sign in to vote.
4.00/5 (1 vote)
Hi All,

Recently I faced a question where I was asked to design an application. This application will have N number of buttons which have shapes mentioned on it(or buttons will be in particular shape e.g. Circle,Triangle). When any shape button is clicked user will be asked for information to calculate area(e.g. radius in case of circle) and then user will be presented with Area of the shape selected.

In order to answer the question I followed below approach.

1. Create abstract class Shape with abstract method Area()
2. All other shapes will implement this Shape class and will implement Area method for specialized calculation for area calculation

Now the interviewer asked me that how to use above structure.

I told that on the handler of button I will create object of particular shape's class and will invoke Area method with it.

But He told that if there are 1000 shapes then you will have to create 1000 handlers. even if you create single handler then inside it you will have to have 1000 if else conditions to create object of particular shape?

I could not answer after this and I'm still wondering how to achieve good design for this?

Please help me guys. Its bugging me since I gave this interview that what would be the ideal design for this?
Posted
Updated 6-Oct-15 2:43am
v5
Comments
Tomas Takac 6-Oct-15 9:00am    
You have these 1000 types of shapes and you only want to have a single handler. So you need to pass this type information into the handler somehow. Now what in C# is designed to pass type information around? Think about it! Programming is about solving problems.
jahanpanahh 7-Oct-15 0:43am    
But I can pass the type information only when I know the type ryt? Here These shape buttons are normal buttons...then clicking on this button how would I know which type is it?
[no name] 10-Oct-15 9:21am    
Dear jahanpanah
Do not bother too much about stupid interview questions. Especially in case the person tell you that there are 1000 shapes. There are some well known shapes (I assume our fingers are enough to count them, unless we are very theoretical) and all the others go to polygons...
Be proud not to work there ;)
Bruno

What I was getting at in my comment was you should use generics. Let's say we have following classes for shapes:
C#
public abstract class ShapeBase
{
    public abstract void Area();
}

public class Circle : ShapeBase
{
    public override void Area() { ... }
}

public class Triangle : ShapeBase
{
    public override void Area() { ... }
}

public class Square : ShapeBase
{
    public override void Area() { ... }
}

Then in your form you have one generic event handler:
C#
private void ButtonClick<TShape>() where TShape: ShapeBase, new()
{
    var shape = new TShape();
    shape.Area();
}

And you register this handler with the respective button clicks using different shape types:
C#
buttonCircle.Click += (sender, args) => ButtonClick<Circle>();
buttonTriangle.Click += (sender, args) => ButtonClick<Triangle>();
buttonSquare.Click += (sender, args) => ButtonClick<Square>();

Voila a single handler used with as many shapes as you want. You can argue you still need to register one thousand event handlers but that was not part of your question.
 
Share this answer
 
Comments
jahanpanahh 7-Oct-15 6:21am    
Hey Tomas,

Thank you for your answer. I understand that multiple handler was not part of my question but you yourself can say whether it would be good design to write thousand lines to register handlers for different buttons?

We all know that in practice we dont see such situation but this was really a interview question and they wanted to test my design skills.

So If I would have given your answer to them I'm sure they would have told me that writing thousand lines for thousand buttons for registering handler is NOT A GOOD DESIGN!!
Tomas Takac 7-Oct-15 7:25am    
I merely extending your design and I strongly believe I answered your question about how to do this using a single handler method without huge IF-ELSE inside. It's very important to know what the requirements are. When given a design assignment in an interview you should not hesitate to ask questions to clarify what needs to be done. It's not a school test.

You are right, this is not a good design. You are dealing with possibly many components not knowing the exact number. I would definitely use dynamic discovery. Read about MEF[^]. Long story short, your form would import all shapes, for each shape dynamically create a button and attach a handler. Each shape should also provide a designer to enter the data needed for area calculation. Try it yourself, if you hit a problem ask a question again.

I like this exercise, very much actually. I think I will use it in the next interview I do. Thank you for inspiration.
jahanpanahh 7-Oct-15 9:01am    
THanks again Tomas for the response.

I wont be able to mark your response as Answer but yeah your links gives some information about how to go about it. I tried to read and understand but I as of now could not understand much.

THanks again!
CPallini 11-Oct-15 15:41pm    
Wow, an OOP solution, eventually. My 5.
Hi, Your question was breaking my heads , here I tried out to find a generic area calculator all you need is to pass co-ordinates and number of sides for your shape ( note in case of circle sides is 1)

I used polygon generic area calculation:

Refer here : http://www.mathopenref.com/coordpolygonarea.html[^]

Shape.cs
___________

C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace GenericAreaCalculator
{
    public class Shape
    {
        public Dictionary<int,int> x;
        public Dictionary<int,> y;

        public Shape()
        {
            x = new Dictionary<int,>();
            y = new Dictionary<int,>();
        }
    }
}


Area.cs
_______

C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace GenericAreaCalculator
{
    public class Area:Shape
    {
        public float CalculateArea(Shape Shapes,int sides)
        {
            float area = 0;
             int x1 = 0;
             int y2 = 0;
             int y1 = 0;
             int x2 = 0;

            if (sides > 1)
            {
                for (int index = 1; index < sides; index++)
                {
                     x1 = Shapes.x[index];
                     y2 = Shapes.y[index + 1];
                     y1 = Shapes.y[index];
                     x2 = Shapes.x[index + 1];
                    area = area + (((x1 * y2)) - ((y1 * x2)));

                }

                 int xn = Shapes.x[sides];              
                 y1 = Shapes.y[1];
                 int yn = Shapes.y[sides];
                 x1 = Shapes.x[1];
                 area = (area + (((xn * y1)) - ((yn * x1))))/2;
                
            }
            else if (sides == 1)
            {
                area = (float)(3.14 * Shapes.x[0] * Shapes.x[0]);
            }
            

            

            return Math.Abs(area);
        }
    }
}


Program.cs
___________

C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace GenericAreaCalculator
{
    class Program
    {
        static void Main(string[] args)
        {
            Shape shapeobj = new Shape();

            shapeobj.x.Add(1, 0);
            shapeobj.x.Add(2, 10);
            shapeobj.x.Add(3, 10);
            shapeobj.x.Add(4, 0);

            shapeobj.y.Add(1, 0);
            shapeobj.y.Add(2, 0);
            shapeobj.y.Add(3, 10);
            shapeobj.y.Add(4, 10);

            Area area = new Area();

            float ShapeArea = area.CalculateArea(shapeobj, 4);

        }
    }
}


Note : Here Index of Co-ordinates have much importance , Make it in sequence
 
Share this answer
 
v2
Comments
[no name] 10-Oct-15 9:43am    
a 5 for your help
jahanpanahh 11-Oct-15 6:12am    
***Just posted below as comment rather than solution which I posted by mistake***

Hey Sreeyush,

Thanks for investing time to find the solution.

Your solution looks good for the problem where one is asked to create solution for generic area calculation.

My question is pretty specific. Based on the shape button clicked calculate the area.

In your solution I will have to find out which particular button was clicked so that I can ask for no of points required for it.

If I can know it then ofcourse I can create object of that particular shape and do the calculation without issue as I have mentioned in my question.

Here the limitation is one do not want to write 1000 conditions to identify which button was clicked.

I hope you got what I wanted to express.
sreeyush sudhakaran 11-Oct-15 7:44am    
Dear friend your question seems to be point less in all aspects without identifying clicked button it is not a magic to calculate area , please get in touch with interviewer I hope he is the only one who can provide solution for your question.You need a Value as input to calculate area that value cannot be be obtained just from a button.
The below is a simple implemtation without using Design Patterns

I think the interviewer asked you about implementation of Observer Pattern

Please refer here about Observer Pattern :

http://www.dofactory.com/net/observer-design-pattern[^]

https://msdn.microsoft.com/en-us/library/ee850490(v=vs.110).aspx[^]

C#
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace ScreenShotDesktop
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Button btn = (Button)sender;

            switch (btn.Text)
            {
                case "Circle" : //Calculate Area of Circle Here
                    break;
                case "Triangle": //Calculate Area of Triangle Here
                    break;
                    //And So on...
            }
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            foreach (Button btn in this.Controls)
            {
                btn.Click += new EventHandler(button1_Click);
            }
        }
    }
}
 
Share this answer
 
v3
Comments
jahanpanahh 7-Oct-15 2:17am    
Hi Sreeyush...Thanks for the reply.

However as I have mentioned in my question,

in your solution if there are say 1000 buttons then one will have to put 1000 cases in side switch statement.

This was not acceptable as per interviewer. He was testing my design skills!!
sreeyush sudhakaran 7-Oct-15 2:45am    
Yes..Instead you can create a Template class To Calculate your Area which Takes your Shape Object as Input , any how you need to calculate areas separately for 1000 objects that cannot be avoided.
jahanpanahh 7-Oct-15 3:19am    
Yeah thats what I also replied to them that there should be ateast some way to know which Shape was called...

But they said that this would be bad design and at the end they told me that you were not able to show your design skills!

Do you know any way by which I just do object.Calculate area and it will calculate area as per the object selected(cirlce,triangle)?
sreeyush sudhakaran 7-Oct-15 10:35am    
you need to get input object from user interface like Textbox according to Button click you need to process this input object and I also don't think they pointed you to solve this problem just like that they expect you to apply some design patterns and OOPS concepts to this question

This question is usually asked in every interview pointed to following OOPS concepts
1) Data Abstraction
2) Use of Virtual Functions
3) Use of Factory Patterns / Abstract factory methods
4) Event Handling can be directed to Observer Pattern
5) Inheritance / Interface usage
6) Usage of Public constructor
7) Usage of Delegates or Callbacks when using 1000 shapes
etc...these are all concepts i see which can be useful in approaching this problem sorry iam also not sure about your interviwer's point of view

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900