Extracting Methods

With the Extract Method operation, you can create (or extract) a new method from multiple lines of code, a single line, or an expression within a given line of code. In each case, the method is created immediately following the method from which the code was extracted. The extracted code is replaced by a call to the new method.

Listing 9.1 provides an example of a method (GetFullInvoice) that is unnecessarily long. We’ve added line numbers for reference purposes. When you’re reviewing code, methods such as these are common and exactly what you should be looking for. The method is designed as a static call that returns a given customer’s Invoice object based on the ID number. However, the invoice and the line items are all retrieved from discrete database calls and stored in domain-specific objects. These objects are then stored on the Invoice instance as properties.


Note

If you would like to follow along in your code editor, download the sample code from the website associated with this book: informit.com/title/9780162337369.


LISTING 9.1 A Long Static Method


01  public class InvoiceDb
02  {
03    public static Invoice GetFullInvoice(int id)
04    {
05      //get invoice table data
06      DataTable dtOrder = DataAccess.GetTableData("Invoice", id);
07
08      //validate invoice against id
09      if (id != (int)dtOrder.Rows[0]["id"])
10      {
11        throw new ApplicationException("Invalid invoice.");
12      }
13
14      //create empty invoice object based on id
15      Invoice invoice = new Invoice(id);
16
17      //get invoice items
18      List<InvoiceLineItem> items = new List<InvoiceLineItem>();
19      DataTable invItems = DataAccess.GetTableData("InvoiceLineItems", id);
20      foreach (DataRow r in invItems.Rows)
21      {
22        InvoiceLineItem item = new InvoiceLineItem(
23          (string)r["name"], (string)r["description"],
24          (double)r["unit_price"], (Int16)r["quantity"]);
25          items.Add(item);
26      }
27      invoice.LineItems = items;
28      return invoice;
29    }
30  }


Opportunities for method extraction inside this one method are numerous. Obvious considerations are the code to initialize the Invoice instance and the code to get invoice line items. Extracting these two chunks of code into discrete methods would result in better organized code (thus, more readable), more opportunities for reuse, and an easier-to-maintain code base. Let’s look at doing these two extractions.

First, let’s extract the code that sets up the Invoice instance. Knowing what to select for extraction requires a bit of experience with the tool. In this case, we will extract lines 05 through 15 (as numbered in the Listing 9.1), which is the code from the first call to DataAccess through the Invoice class initialization. Figure 9.14 shows the selected code and related light bulb menu to access the Extract Method refactor.

Image

FIGURE 9.14 Select the code to refactor, invoke the light build menu, and choose options to Extract Method.

Invoking the Extract Method refactor creates a new method from your selected code along with the appropriate parameters and return type. It also replaces the extracted code with a reference call to this new method. Finally, Visual Studio invokes the Rename refactor so you can give your new method a name that makes sense. Figure 9.15 shows the extracted method, the call to the extracted method, and the results of renaming the new method inside the IDE.

Image

FIGURE 9.15 The refactored method and the resulting Rename operation.

Next, let’s extract the code that builds a list of invoice items and adds them to the Invoice object. We begin by selecting the code represented by lines 17 through 26 in Listing 9.1. Note that we do not want to select the call to set the invoice’s LineItems property (line 27); we simply want to return an object that represents all line items for a given invoice.

Figure 9.16 shows the method extraction. In this case, we name the new method GetInvoiceItems. Notice that the method takes a parameter named id. It would likely be helpful to rename this parameter invoiceId.

Image

FIGURE 9.16 The code after refactoring the call to get invoice line items.

The newly organized (and much shorter) original method looks like Listing 9.2. In addition, you now have two new tight, discrete methods that you may be able to reuse in the future (and perhaps make public). These new methods are in Listing 9.3.

LISTING 9.2 The Original Long Static Method After the Extractions


public static Invoice GetFullInvoice(int id)
{
  Invoice invoice = GetInvoice(id);

  //get invoice items
  List<InvoiceLineItem> items = GetInvoiceItems(id);
  invoice.LineItems = items;

  return invoice;
}


LISTING 9.3 The Extractions


private static List<InvoiceLineItem> GetInvoiceItems(int invoiceId)
{
  List<InvoiceLineItem> items = new List<InvoiceLineItem>();
  DataTable invItems = DataAccess.GetTableData("InvoiceLineItems", invoiceId);
  foreach (DataRow r in invItems.Rows)
  {
    InvoiceLineItem item = new InvoiceLineItem(
      (string)r["name"], (string)r["description"],
      (double)r["unit_price"], (Int16)r["quantity"]);
    items.Add(item);
  }

  return items;
}

private static Invoice GetInvoice(int id)
{
  //get invoice table data
  DataTable dtOrder = DataAccess.GetTableData("Invoice", id);

  //validate invoice against id
  if (id != (int)dtOrder.Rows[0]["id"])
  {
    throw new ApplicationException("Invalid invoice.");
  }

  //create empty invoice object based on id
  Invoice invoice = new Invoice(id);
  return invoice;
}



Note

The Extract Method does not allow you to choose where to put the extracted method. Many times, you might find a bit of code that really needs to be extracted into a method of another, different class. For this, you have to extract the method and then move things around manually.


..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset