Reducing coupling simple example needed for beginner
Asked Answered
A

3

7

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).

Astray answered 9/5, 2012 at 10:58 Comment(2)
What exactly don't you understand? Which concept are you having difficulties with?Handout
I know what coupeling and cohesion means in theory. But I dont understand how to code it. Especially as we never covered interfaces in college (yea, I know, great college). I do understand interfaces too, but I dont know how to use them to get coupeling reduced.Astray
A
4

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. :)

Affricative answered 9/5, 2012 at 11:11 Comment(4)
So far this answer seems the easiest to understand. I am currently playing around with it and will get back to you. The only problem I am having is the links you provided get into a lot of dept quite quickly and for this simple example, understanding is more important. I would award you the answer if you can write the code needed without the extensions instead of the MainMethod_InInterfaceLayer(). Perhaps by changing what I should do in the MainWindow code behind if possible. Thanks for your help so far.Astray
I've updated my answer. Hopefully, in conjunction to @Oded's answer, it should be what you're looking for.Affricative
Thanks Richard. I am just implementing your answer now and the explanation behind it is very nice. I am going to assume that my example is too simple for it to reduce Visual Studios Coupling mark from 3 to 2 on the methods mentioned. As explained in my edits, no reduction happens when I do as you described. Thanks for your help with this. I will play with your side note too, but I have a feeling this is somewhat unrelated (although I appreicate the suggestion). I would like to know the benifit of lazy loading in this case and what line of taught baught you to suggesting it if you have time.Astray
Just adding as a side note, if you do not intend to reinitialize the _CurrentPerson field, then you don't need a setter for the CurrentPerson the property. Also, if you like syntax sugar, you can replace the whole CurrentPerson property by: private IPerson CurrentPerson => _CurrentPerson ?? (_CurrentPerson = new Person());Gimmick
H
3

Say you have an IPerson interface and several implementation (Person, Student, Teacher etc) and you have some code that simply needs to operate on an IPerson.

Having:

IPerson x = new Person();

in your code behind strongly couples it to the Person class.

Inversion of control comes into play by having the dependencies coming from outside instead of creating the inside the class.

This is normally achieved by using dependency injection - an IPerson being passed into the class instead of the class creating it directly. You can do that by passing an instance to the constructor (constructor injection) or as a property (property injection).

Service locator is another way to get dependencies without hard coding them - the pattern "locates" an instance for a type/interface.

An example of how to inject a dependency to a class:

public class MyClass
{
  IPerson person;

  public MyClass(IPerson p)
  {
    person = p; // injected an instance of IPerson to MyClass
  }

  // can now use person in any method of the class, or pass it around:

  public void MyMethod()
  {
     string name = person.Name;
  }
}
Handout answered 9/5, 2012 at 11:15 Comment(2)
First let me thank you for your answer. Using the code in richards answer I was able to make an interface so far. The problem I am now having is how to use that instead of the code in the code behind. Or is that what you are showing me above. Its not quite clear to me but if you can clarify with more code, I will award you the answer. Thanks again.Astray
@FrancisRodgers - Added an example of how a class MyClass is decoupled from any implementation of IPerson, so any implementer can be used. Also showing a case of constructor injection.Handout
O
0

Suppose you have a Person class that can load itself from database, get changed and send email when he or she died.

class Person 
{
    ...
    void LoadUsingId(int id);
    void HaveDiedWillMail();
    void SetFirstName(string name);
    ...
}

What you can see here is that this Person is actually doing three things (at the least!).

It knows how to talk to a database to load itself. It knows how to send email. It can change itself.

Any code, in theory if not practise, should be responsible for only one thing. To reduce the coupling between these components, you must pull them apart. Decouple them so they can work independantly.

class Person 
{
    ...
    void LoadUsingId(PersonRepository person);
    void HaveDiedWillMail(IMailer mailer);
    void SetFirstName(string name);
    ...
}

In this contrived example, the Person has no idea how to load something from a database. Ignoring the fact that -loading- is something you should decouple too. Mail sending too has been decoupled, since you tell the Person.HaveDiedWillMail that you want to use a particular mailer (IMailer mailer).

Dependency injection, Service containers and such technology automatically find the components your Person needs/wants in order to function, sort of an extra layer on top of decoupling to make it easier to wire all the seperate parts together.

Oomph answered 9/5, 2012 at 11:15 Comment(2)
I disagree that an object (a model) should load itself from the database, even in a loosely coupled way. A model should do one thing: represent a real object. Loading from the database is the job of another object, which will do one thing: load data from the database. In fact, two layers in between the model and the database would be great.Bootjack
I agree with you too. But I am not trying to explain everything here or even what is sensible ... but decoupling.Oomph

© 2022 - 2024 — McMap. All rights reserved.