Search code examples
c#decouplingcouplingloose-coupling

Reducing coupling simple example needed for beginner


Just out of college and am coming across some code where I need to reduce coupling. But I don’t understand fully all the concepts and would like a simple example to help me. To get you started I have a person class with a single field, name. I have a method within that class to concatenate some text.

I know this is a silly example, and most people would never consider reducing coupling in situations as simple as this but I only want a simple example to help me fully understand the code and concepts together.

In the code behind the main window I put a text box, and a button. When the window loads it shows the current value of the person x name field. When the button is clicked, the x.PersonAddText method is called. Currently this example has coupling calculated at 8. With a 3 for the button click event and a 3 for the window loaded event.

Is there any way, using this example we can get it down to less than this for either or both of them.

Below is all my code:

My Person Class:

public class Person
{
    //Fields
    private string name;

    //Properties
    public string Name
    {
        get { return name; }
        set { name = value; }
    }

    //Constructors
    public Person()
    {
        name = "joe";
    }

    //Methods
    public string PersonAddText(string text)
    {
        return name += " - " + text;
    }

    //Interfaces (or additional code below here please to aid understanding)
}

My Code Behind:

    Person x = new Person();

    public MainWindow()
    {
        InitializeComponent();
    }

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        txtname.Text = x.Name;
    }

    private void button1_Click(object sender, RoutedEventArgs e)
    {
        txtname.Text = x.PersonAddText(txtname.Text);
        txtname.Text = x.Name;
    }

My Simple XAML:

<Grid>
    <TextBox Name="txtname" Margin="12,12,12,0" Height="23" VerticalAlignment="Top" />
    <Button Content="Add Text" Margin="12,41,12,0" Name="button1" VerticalAlignment="Top" Click="button1_Click" />
</Grid>

I am having great difficulty understanding the tutorials around the internet explaining this. From what I see there are 3 ways to do this (it would be nice if possible, to have my code above converted to an example of all three):

  • Service Locator
  • Dependency Injection
  • Inversion of control (IoC)

The article explaining the stuff i have read is excellent, but the examples are not relevant to me as he is using VB and ASP.Net with database connection strings. This is totally opposite what I need, and I don’t want to be thinking about how to translate the code, while learning the concepts, and thinking also about how to apply it to something relevant. While the example is good, it’s just too much, and I would really appreciate any extra help.

Edit History: Corrected spellings. Added the following to clarify my question:

I understand the theory behind coupling and coheasion and why you should reduce one and increase the other. But we never got to code any examples in college. Also, while not covered in college, I do understand interfaces. However, I dont understand how to use them to reduce coupling.

Added a link to the article I refrenced above.

Edit 2: So far what I have now got is the following:

public interface IPerson 
{ 
    string Name { get; set; } 
    string PersonAddText(string text); 
} 

public class Person : IPerson 
{
    //The code from the person class above
}

How do I now use this in the mainwindow code behind? I am guessing I should replace

Person x = new Person();

with

IPerson x = new Person(); 

Is this correct, and if so, is there anything else I need to do. The reason I ask is because I still dont see any reduction in code coupling figures reported by visual studio (infact, it increases it by 1 on the main window code behind).


Solution

  • Edit

    I'm glad my answer helped a bit, let me update it slightly further. To use your question as a direct answer, all you would need to change is your field declaration from:

    Person x = new Person();
    

    to

    IPerson x = new Person();
    

    Your code-behind now know the properties and methods that are specified in your interface, and is a lot less coupled, as you could swap out new Person() for new Student() later-on. As long as the object implements the interface. Your code-behind should now work without any necessary changes.

    Side note

    I would recommend considering lazy-loading the x person, and also using a property with a more recognisable name. N.B. this doesn't answer your question, but it's just a suggestion. :)

    private IPerson _CurrentPerson = null;
    private IPerson CurrentPerson
    {
        get
        {
            if (this._CurrentPerson == null)
            {
                this._CurrentPerson = new Person();
            }
            return this._CurrentPerson
        }
        set
        {
            this._CurrentPerson = value;
        }
    }
    

    De-coupling is when two, or more, code blocks should not depend on each other. Inversion of Control is when the coupling of objects is bound at runtime, thus allowing for much more flexibility, and therefore less coupling, of objects and their instances. Inversion of control is best use in conjunction with interfaces. The interfaces define that ClassA will do MethodX and have PropertyY. Our main object does not care what object is returned at run-time, as log as it can fulfil an interface, it's happy.

    In your above example, you will want to interface your person class, maybe something like so:

    public interface IPerson
    {
        string Name { get; set; }
        string PersonAddText(string text);
    }
    
    public class Person : IPerson
    {
        // your code here
    }
    

    Then, within your main method calls, instead of explicitly using a Person object, you will use an instance of an object that implements the interface IPerson. The "hooking" up of the interface and the object can be achieved by various different libraries which will help in setting up your dependencies. In my experience I've used StructureMap and Microsoft's Enterprise Library. They can be a bit fiddly to set-up, but once they are, you'll be able to do something like so...

    public void MainMethod_InInterfaceLayer()
    {
        // container is an instance of UnityContainer
        Person newPerson = container.Resolve<IPerson>();
    }
    

    I know this ins't a full answer, but hopefully it'll help a bit. :)