Convert a Large Switch Method to a Factory

Say you have a switch statement with large blocks of code in it.
See the example below.(and use your imiganation)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
 
public enum SHAPES { Circle, Square, Rectangle, Triangle };
 
public class SwitchMethod
    {
        public static void draw(SHAPES shape)
        {
            switch (shape)
            {
                case SHAPES.Circle:
                    // 1000 lines of code...
                    Console.WriteLine("Circle.draw()");
                    break;
 
                case SHAPES.Rectangle:
                    // 1000 lines of code...
                    Console.WriteLine("Rectangle.draw()");
                    break;
 
                case SHAPES.Square:
                    // 1000 lines of code...
                    Console.WriteLine("Square.draw()");
                    break;
 
                case SHAPES.Triangle:
                    // 1000 lines of code...
                    Console.WriteLine("Triangle.draw()");
                    break;
            }
        }
    }

And you call it like this:

1
2
3
4
5
6
7
8
9
 
   class Program
    {
        static void Main(string[] args)
        {
            SwitchMethod.draw(SHAPES.Circle);
            Console.ReadKey();
        }
    }

PROBLEM:
[1] You have a large file, making it hard to understand.
[2] The Single responsibility principle is violated. 1 class – many shapes.
If you have one developer working on tirangles and another on Circles. There is going to be a conflict at check-in, (no matter what source control system you are using)

SOLUTION:
[1] Break up the switch cases into classes.
* Each class should implement a common interface.
* Each class should be in its own file.

[2] Now we need a clean method to call them.
* Add a Boolean canDraw(SHAPES shape) to the interface.
* The class returns true if it can draw the shape.

1
2
3
4
5
6
7
  public enum SHAPES { Circle, Square, Rectangle, Triangle };
 
    public interface Shape
    {
        Boolean canDraw(SHAPES shape);
        void draw();
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
 
   public class Circle : Shape
    {
        public bool canDraw(SHAPES shape)
        {
            return shape == SHAPES.Circle;
        }
 
        public void draw()
        {
            Console.WriteLine("Circle.draw()");
        }
 
    }
 
    public class Square : Shape
    {
        public bool canDraw(SHAPES shape)
        {
            return shape == SHAPES.Square;
        }
 
        public void draw()
        {
            Console.WriteLine("Square.draw()");
        }
 
    }
 
    public class Rectangle : Shape
    {
 
        public bool canDraw(SHAPES shape)
        {
            return shape == SHAPES.Rectangle;
        }
 
        public void draw()
        {
            // 100 lines of code...
            Console.WriteLine("Rectangle.draw()");
        }
 
    }
 
    public class Triangle : Shape
    {
 
        public bool canDraw(SHAPES shape)
        {
            return shape == SHAPES.Triangle;
        }
 
        public void draw()
        {
            // 100 lines of code...
            Console.WriteLine("Triangle.draw()");
        }
    }

[3] Now make a shapeFactory.
* Make a static List containing instances of each class.
* add a getter that returns the first class that canDraw the shape.

The List/canDraw are replacing the switch. CPU cycles have been exchanged for readability.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
 
    public abstract class ShapeFactory
    {
        private static List shapelist = new List(){
            new Circle(),
            new Square(),
            new Rectangle(),
            new Triangle()
        };
        public static Shape getShape(SHAPES name)
        {
            return shapelist.First(a => a.canDraw(name));
        }
    }

And we call it like this…

1
2
3
4
5
6
7
8
9
class Program
    {
        static void Main(string[] args)
        {
 
            ShapeFactory.getShape(SHAPES.Circle).draw();
            Console.ReadKey();
        }
    }

One note, you could do away with the factory class and canDraw and just call an instance of a shape from within the SwitchMethod cases.