Refactoring ClassA.ClassB.ThingC

When ThingC() is a method:

?
 
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
using System;
 
namespace ClassAClassBThingC
{
    class Program
    {
        static void Main(string[] args)
        {
            ClassA classA = new ClassA();
 
            classA.classB.DoSomething();
        }
    }
 
    class ClassA
    {
        public ClassB classB = new ClassB();
    }
 
    public class ClassB
    {
        public void DoSomething()
        {
            Console.WriteLine("Hello World!");
        }
    }
}
 
 
using System;

namespace ClassAClassBThingC
{
    class Program
    {
        static void Main(string[] args)
        {
            ClassA classA = new ClassA();

            classA.classB.DoSomething();
        }
    }

    class ClassA
    {
        public ClassB classB = new ClassB();
    }

    public class ClassB
    {
        public void DoSomething()
        {
            Console.WriteLine("Hello World!");
        }
    }
}

Notice line 11.

Refactor:
classA.classB.DoSomething();
to
classA.DoSomething();

Add method DoSomething() to ClassA and have it call classB.DoSomething().

In other words, make it the responsibility of ClassA to give you access to DoSomething().

This gets rid of class Program’s dependency on ClassB.

The refactored code looks like:

?
 
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
using System;
 
namespace ClassAClassBThingC
{
    class Program
    {
        static void Main(string[] args)
        {
            ClassA classA = new ClassA();
 
            classA.DoSomething();
        }
    }
 
    class ClassA
    {
        public ClassB classB = new ClassB();
 
        public void DoSomething()
        {
            classB.DoSomething();
        }
    }
 
    public class ClassB
    {
        public void DoSomething()
        {
            Console.WriteLine("Hello World!");
        }
    }
}
 
 
using System;

namespace ClassAClassBThingC
{
    class Program
    {
        static void Main(string[] args)
        {
            ClassA classA = new ClassA();

            classA.DoSomething();
        }
    }

    class ClassA
    {
        public ClassB classB = new ClassB();

        public void DoSomething()
        {
            classB.DoSomething();
        }
    }

    public class ClassB
    {
        public void DoSomething()
        {
            Console.WriteLine("Hello World!");
        }
    }
}

Notice how class Program no longer has a reference to ClassB. Class Program is no longer dependent on ClassB.

Now notice that ClassA creates an instance of ClassB and holds on to it. Another optional refactoring we can do is pass and instance of ClassB into ClassA so ClassA doesn't have to create it. This is known as "Dependency Injection."

Whenever you see a class creating and storing a reference to another class, consider the possibility of passing the class in as a constructor parameter instead. This tends to make the class easier to unit test.

Let's do that here. Create ClassB in the Main program and pass it as a parameter to the ClassA constructor:

?
 
01
02
03
04
05
06
07
08
09
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
using System;
 
namespace ClassAClassBThingC
{
    class Program
    {
        static void Main(string[] args)
        {
            ClassB classB = new ClassB();
            ClassA classA = new ClassA(classB);
 
            classA.DoSomething();
        }
    }
 
    class ClassA
    {
        public ClassB classB;
 
        public ClassA(ClassB classB)
        {
            this.classB = classB;
        }
 
        public void DoSomething()
        {
            classB.DoSomething();
        }
    }
 
    public class ClassB
    {
        public void DoSomething()
        {
            Console.WriteLine("Hello World!");
        }
    }
}
 
 
using System;

namespace ClassAClassBThingC
{
    class Program
    {
        static void Main(string[] args)
        {
            ClassB classB = new ClassB();
            ClassA classA = new ClassA(classB);

            classA.DoSomething();
        }
    }

    class ClassA
    {
        public ClassB classB;

        public ClassA(ClassB classB)
        {
            this.classB = classB;
        }

        public void DoSomething()
        {
            classB.DoSomething();
        }
    }

    public class ClassB
    {
        public void DoSomething()
        {
            Console.WriteLine("Hello World!");
        }
    }
}

It may at first appear that all we did was move the reference to ClassA back to class Program, which may sound silly, because we just refactored the code to get rid of the reference to ClassA in class Program, and here we are moving it right back again!

However, notice one important difference: class Program isn't actually using ClassB. It's just creating ClassB and handing it to someone else.

The original code had the line classA.classB.DoSomething();, we were counting on ClassB having a public DoSomething() method. This new refactored code makes no such call or assumption.

This refactoring may have made it easier to unit test; however, we still have a reference to ClassB in ClassA. To get rid of that, we can use the “Hollywood Principle”.

?
 
01
02
03
04
05
06
07
08
09
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
using System;
 
namespace ClassAClassBThingC
{
    class Program
    {
        static void Main(string[] args)
        {
            ClassA classA = new ClassA();
            ClassB classB = new ClassB();
 
            classA.DoSomething();
        }
    }
 
    class ClassA
    {
        public static event EventHandler SomeEvent;
 
        public void DoSomething()
        {
            SomeEvent?.Invoke(this, new EventArgs());
        }
    }
 
    public class ClassB
    {
        public ClassB()
        {
            ClassA.SomeEvent += this.DoSomething;
        }
 
        public void DoSomething(object sender, EventArgs e)
        {
            Console.WriteLine("Hello World!");
        }
    }
}
 
 
using System;

namespace ClassAClassBThingC
{
    class Program
    {
        static void Main(string[] args)
        {
            ClassA classA = new ClassA();
            ClassB classB = new ClassB();

            classA.DoSomething();
        }
    }

    class ClassA
    {
        public static event EventHandler SomeEvent;

        public void DoSomething()
        {
            SomeEvent?.Invoke(this, new EventArgs());
        }
    }

    public class ClassB
    {
        public ClassB()
        {
            ClassA.SomeEvent += this.DoSomething;
        }

        public void DoSomething(object sender, EventArgs e)
        {
            Console.WriteLine("Hello World!");
        }
    }
}

This is the classic “Publish / Subscribe” design pattern. ClassA publishes an event which anyone interested may subscribe to.

Now ClassB could clange, or could even disappear, and ClassA won’t get upset about it.

Technically, if you run this program and trace the flow of execution, we still have ClassA calling the ClassB DoSomething() method. The call just looks different now. Instead of:

?
 
20
21
22
23
public void DoSomething()
{
    classB.DoSomething();
}
 
 
public void DoSomething()
{
    classB.DoSomething();
}
we now have:
?
 
20
21
22
23
public void DoSomething()
{
    SomeEvent?.Invoke(this, new EventArgs());
}
 
 
public void DoSomething()
{
    SomeEvent?.Invoke(this, new EventArgs());
}

SomeEvent is a list which ClassB adds it's DoSomething() method to. When ClassA invokes SomeEvent it goes through the methods on the SomeEvent list and calls each one. Since DoSomething() is on the list, ClassA calls it.

Back to Refactoring Index

Back to Programming Index

Back to DELEY’S Home Page