Monday, December 27, 2010

#03 - How CSharp design patterns and refactoring differ from other languages - LINQ

This post continuing the post "How CSharp design patterns and refactoring differ from other languages - Part 01" and is based on Martin Fowler's "Refactoring" book.

Now here comes the first major difference between Java and CSharp
The next refactoring step is to extract Customer.GetTotalCharge() out of the loop of the enumerated rentals.

Making it the naive way it will look as folows:
        public double GetTotalCharge()
{
double result = 0;
foreach (var rental in _rentals)
result += rental.GetCharge();

return result;
}
But it could look much more elegant this way:
        public double GetTotalCharge()
{
return _rentals.Sum((Rental r) => r.GetCharge());
}
The only non-intutive part was that you have to first add "using System.Linq;" statement.

I'm not getting into how to work with LINQ, Anonymous methods and Lambbda Expressions, the same way I'm not getting into "Why refactoring".
I assume you have much better resources for that than this set of posts.

now that the extracted method became a one-liner (62 charaters long including the indentation) one might want to consider making it an inline statement.
I prefer it as a separate method for testing purposes.

* Actually we can shorten it to: "return _rentals.Sum((r) => r.GetCharge());"
As the type "Rental" is implied from _rentals.

Doing so for GetCharge and GetFrequentRenterPoints and - TADA!

Now the code for class Customer looks this way

using System.Collections;
using System.Collections.Generic;
using System.Linq;

namespace Refactoring
{
public class Customer
{
public string Name { get; private set; }
List _rentals = new List();

public Customer(string name)
{
Name = name;
}

public void AddRental(Rental rental)
{
_rentals.Add(rental);
}

public string Statement()
{
IEnumerable rentals = _rentals;
string result = "Rental Record for " + Name + "\n";

foreach (Rental each in rentals)
{
// show figures for this rental
result += "\t" + each.Movie.Title + "\t" + each.GetCharge() + "\n";
}

// add footer
result += "Amount owed is " + GetTotalCharge() + "\n";
result += "You earned " + GetFrequentRenterPoints() + " frequent renter points";

return result;
}

public double GetTotalCharge()
{
return _rentals.Sum((r) => r.GetCharge());
}
public double GetFrequentRenterPoints()
{
return _rentals.Sum((r) => r.GetFrequentRentalPoints());
}
}
}
Hope you find it useful

Dekel

No comments: