Refactoring: adapt parameter

Sometimes you are not able to use Extract Interface refactoring because interface of parameter may be too large or there may be no interface at all. You just have class to pass in and you are not able to fake it or extend it to get class testable. In this case you have to use Adapt Parameter refactoring to create adapter that is seen through common some common class of interface.

Let’s look at the following code.

public class CustomerCardService
{
   
//...

   
public bool IsValidCustomer(MagneticStripeCardReader
reader)
    {
       
var
customerCode = reader.ReadCustomerCode();
       
var
expiryDate = reader.ReadExpiryDate();

       
var
customer = _repository.GetByCode(customerCode);
       
if (customer == null
)
           
return false
;

       
return
(expiryDate > DateTime.Now);
    }

   
// ...
}

Here we can see a method that accepts class MagneticStripeCardReader. This class implements no interfaces and we are not able to extend it. We cannot fake it and we cannot go to interfaces. To get over this problem let’s create interface that we can use to make this method testable.

public interface ICustomerDataReader
{
   
string ReadCustomerCode();
    DateTime ReadExpiryDate();
}

As a next thing we have to modify this method to make it accept our new interface. All we have to do is to change parameter signature.

public bool IsValidCustomer(ICustomerDataReader reader)
{
   
// ...
}

After that let’s write fake class we can use to test this method.

public class FakeCardReaderSource : ICustomerDataReader
{
   
private string
_customerCode;
   
private
DateTime _expiryDate;
 
   
public FakeCardReader(string
customerCode, DateTime expiryDate)
    {
        _customerCode = customerCode;
        _expiryDate = expiryDate;
    }
 
   
public string
ReadCustomerCode()
    {
       
return
_customerCode;
    }
 
   
public
DateTime ReadExpiryDate()
    {
       
return _expiryDate;
    }
}

Now we are almost finished. All we need to do is to write adapter class for MagneticStripeCardReader.

public class MagneticStripeSource : ICustomerDataReader
{
   
private MagneticStripeCardReader
_reader;

   
public MagneticStripeSource(MagneticStripeCardReader
reader)
    {
        _reader = reader;
    }

   
public string
ReadCustomerCode()
    {
       
return
_reader.ReadCustomerCode();
    }

   
public
DateTime ReadExpiryDate()
    {
       
return _reader.ReadExpiryDate();
    }
}

Besides testability we achieved one thing more – we can easily create adapters for other types of card reader classes (by example, we may have SmartCardReader in the future). In current case we were happy – we had made no modifications to original method body. But in real world we usually have to modify also method body.

Gunnar Peipman

Gunnar Peipman is ASP.NET, Azure and SharePoint fan, Estonian Microsoft user group leader, blogger, conference speaker, teacher, and tech maniac. Since 2008 he is Microsoft MVP specialized on ASP.NET.

    Leave a Reply

    Your email address will not be published. Required fields are marked *