Refactoring ClassA.ClassB.ThingC

When ThingC() is a Property:

Refactor:
var s = classA.classB.SomeValue;
to
var s = classA.SomeValue;

Add property SomeValue to ClassA and have it fetch the value from classB.SomeValue;.

In other words, make it the responsibility of ClassA to give you access to SomeValue.

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

Example:
?
 
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
39
40
41
42
43
44
45
46
using System.ComponentModel;
using System.Runtime.CompilerServices;
 
namespace ClassAClassBThingC
{
    class Program
    {
        static void Main(string[] args)
        {
            ClassA classA = new ClassA();
 
            var s = classA.classB.SomeValue;
        }
    }
 
    class ClassA
    {
        public ClassB classB = new ClassB();
    }
 
    class ClassB : INotifyPropertyChanged
    {
        private string someValue = "Hello World!";
        public string SomeValue
        {
            get
            {
                return someValue;
            }
            set
            {
                if (someValue != value)
                {
                    someValue = value;
                    NotifyPropertyChanged();
                }
            }
        }
 
        public event PropertyChangedEventHandler PropertyChanged;
        protected void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
        {
            this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
 
 
using System.ComponentModel;
using System.Runtime.CompilerServices;

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

            var s = classA.classB.SomeValue;
        }
    }

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

    class ClassB : INotifyPropertyChanged
    {
        private string someValue = "Hello World!";
        public string SomeValue
        {
            get
            {
                return someValue;
            }
            set
            {
                if (someValue != value)
                {
                    someValue = value;
                    NotifyPropertyChanged();
                }
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        protected void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
        {
            this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

Notice line 12.

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
using System.ComponentModel;
using System.Runtime.CompilerServices;
 
namespace ClassAClassBThingC
{
    class Program
    {
        static void Main(string[] args)
        {
            ClassA classA = new ClassA();
 
            var s = classA.SomeValue;
        }
    }
 
    class ClassA
    {
        public ClassB classB = new ClassB();
 
        public string SomeValue
        {
            get { return classB.SomeValue; }
            set { classB.SomeValue = value; }
        }
    }
 
    class ClassB : INotifyPropertyChanged
    {
        private string someValue = "Hello World!";
        public string SomeValue
        {
            get
            {
                return someValue;
            }
            set
            {
                if (someValue != value)
                {
                    someValue = value;
                    NotifyPropertyChanged();
                }
            }
        }
 
        public event PropertyChangedEventHandler PropertyChanged;
        protected void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
        {
            this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
 
 
using System.ComponentModel;
using System.Runtime.CompilerServices;

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

            var s = classA.SomeValue;
        }
    }

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

        public string SomeValue
        {
            get { return classB.SomeValue; }
            set { classB.SomeValue = value; }
        }
    }

    class ClassB : INotifyPropertyChanged
    {
        private string someValue = "Hello World!";
        public string SomeValue
        {
            get
            {
                return someValue;
            }
            set
            {
                if (someValue != value)
                {
                    someValue = value;
                    NotifyPropertyChanged();
                }
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        protected void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
        {
            this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

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

This is a common occurrance which happens as programs grow. A programmer wants to get a value, the programmer knows where the value is, so the programmer just reaches through a circuitous route to get the value. It's fast and it gets results. So go ahead and do it if you're just playing with code to see if you can get something that works; however, be aware that this will need to be refactored out.

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. In the Main program create ClassB 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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
using System.ComponentModel;
using System.Runtime.CompilerServices;
 
namespace ClassAClassBThingC
{
    class Program
    {
        static void Main(string[] args)
        {
            ClassB classB = new ClassB();
            ClassA classA = new ClassA(classB);
 
        var s = classA.SomeValue;
        }
    }
 
    class ClassA
    {
        public ClassB classB;
 
        public ClassA(ClassB classB)
        {
            this.classB = classB;
        }
 
        public string SomeValue
        {
            get { return classB.SomeValue; }
            set { classB.SomeValue = value; }
        }
    }
 
    class ClassB : INotifyPropertyChanged
    {
        private string someValue = "Hello World!";
        public string SomeValue
        {
            get
            {
                return someValue;
            }
            set
            {
                if (someValue != value)
                {
                    someValue = value;
                    NotifyPropertyChanged();
                }
            }
        }
 
        public event PropertyChangedEventHandler PropertyChanged;
        protected void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
        {
            this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
 
 
using System.ComponentModel;
using System.Runtime.CompilerServices;

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

        var s = classA.SomeValue;
        }
    }

    class ClassA
    {
        public ClassB classB;

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

        public string SomeValue
        {
            get { return classB.SomeValue; }
            set { classB.SomeValue = value; }
        }
    }

    class ClassB : INotifyPropertyChanged
    {
        private string someValue = "Hello World!";
        public string SomeValue
        {
            get
            {
                return someValue;
            }
            set
            {
                if (someValue != value)
                {
                    someValue = value;
                    NotifyPropertyChanged();
                }
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        protected void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
        {
            this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}


Back to Refactoring Index

Back to Programming Index

Back to DELEY’S Home Page