Tuesday, December 21, 2010

How CSharp design patterns and refactoring differ from other languages - Part 01

I'm reading Martin Fowler's "Refactoring" book, and recalling a course I had long ago about design patterns.

Now - these are extreamly useful tools, as you probably know, but...
When dealing with CSharp (and esspecially .Net 4.0) you have an extended set of tools that make some things so elegant it changes the way you can refactor and apply patterns.

The simplest example is "delegate" (and "anonymous delegate")
In the old-school of design patters we talk about classes and interfaces, while nowdays you can call the same method and pass it different worker delegate so easily, it changes the way you think about your code.

On the first chapter of Fowler's book (Where the examples are in Java) he shows extacting out a while statement that takes 6 lines of code, while using LINQ it would be a one-liner, and a readable one.

All of that said in order to explain that there should or at least could be a sub-version of both "Design Patterns" and "Refactoring" that is .Net specific and makes use of the great new features.

And now I need to get to work on getting the examples and translate them into CSharp.

So here is the initial code translated to CSharp
Note the different notation for class properties, Enumerations and const declerations
No deep change

---
namespace Refactoring
{
public class Movie
{
public const int CHILDRENS = 2;
public const int REGULAR = 0;
public const int NEW_RELEASE = 1;

public int PriceCode { get; set; }
public string Title { get; private set; }

public Movie(string title, int priceCode)
{
Title = title;
PriceCode = priceCode;
}
}
}
---
namespace Refactoring
{
public class Rental
{
public Movie Movie { get; private set; }
public int DaysRented { get; private set; }

public Rental(Movie movie, int daysRented)
{
Movie = movie;
DaysRented = daysRented;
}
}
}
---
using System.Collections;
using System.Collections.Generic;

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()
{
double totalAmount = 0;
int FrequentRenterPoints = 0;
IEnumerable rentals = _rentals;
string result = "Rental Record for " + Name + "\n";

foreach (Rental each in rentals)
{
double thisAmount = 0;

// Determine amount for each line
switch (each.Movie.PriceCode)
{
case Movie.REGULAR:
thisAmount += 2;
if (each.DaysRented > 2)
thisAmount += (each.DaysRented - 2) * 1.5;
break;
case Movie.NEW_RELEASE:
thisAmount += each.DaysRented * 3;
break;
case Movie.CHILDRENS:
thisAmount += 1.5;
if (each.DaysRented > 3)
thisAmount += (each.DaysRented - 3) * 1.5;
break;
}

// Add frequent renter points
FrequentRenterPoints++;
if (each.Movie.PriceCode == Movie.NEW_RELEASE &&
each.DaysRented > 1)
FrequentRenterPoints++;

// show figures for this rental
result += "\t" + each.Movie.Title + "\t" + thisAmount + "\n";
totalAmount += thisAmount;
}

// add footer
result += "Amount owed is " + totalAmount + "\n";
result += "You earned " + FrequentRenterPoints + " frequent renter points";

return result;
}
}
}
---

* Sorry for the missing indentation, you can paste it to VS and let it fix it

Let me know if you find this helpful.

No comments: