Move Method
Before you begin: Objects, methods, fields, and parameters.
Move Method relocates behavior to another class or module, then updates callers to use its new home. It is useful when a method works mainly with another object’s data and naturally describes something that object does. 1
Original version: a fare calculator borrows everything
A trip stores its distance and price per distance unit. A separate calculator reads both values to multiply them. Use small nonnegative integers here; currency rounding is not part of this example.
public sealed class Trip
{
public int Distance { get; }
public int PricePerUnit { get; }
public Trip(int distance, int pricePerUnit)
{
Distance = distance;
PricePerUnit = pricePerUnit;
}
}
public sealed class FareCalculator
{
public int For(Trip trip)
{
return trip.Distance * trip.PricePerUnit;
}
}FareCalculator has no data of its own. Its method reads two properties of Trip and performs a trip-specific calculation.
class Trip:
def __init__(self, distance, price_per_unit):
self.distance = distance
self.price_per_unit = price_per_unit
class FareCalculator:
def for_trip(self, trip):
return trip.distance * trip.price_per_unitThe calculator uses only the trip’s distance and rate. The calculation has a plausible home on the trip itself.
Refactored version: ask the trip for its fare
public sealed class Trip
{
public int Distance { get; }
public int PricePerUnit { get; }
public Trip(int distance, int pricePerUnit)
{
Distance = distance;
PricePerUnit = pricePerUnit;
}
public int Fare()
{
return Distance * PricePerUnit;
}
}The caller changes from new FareCalculator().For(trip) to trip.Fare(). The calculation and result remain the same.
class Trip:
def __init__(self, distance, price_per_unit):
self.distance = distance
self.price_per_unit = price_per_unit
def fare(self):
return self.distance * self.price_per_unitThe caller changes from FareCalculator().for_trip(trip) to trip.fare(). For distance 8 and rate 3, either version returns 24.
Move responsibility, not merely text
Create the method at its destination, redirect the old method temporarily if callers need a gradual migration, then remove the forwarding method when it is safe. Check access to private fields, overridden methods, side effects, and external API users before deleting anything.
A separate calculator can be appropriate when pricing is an independent policy used with many trip types, or when the model intentionally uses plain data and functions. Do not move a function into a class merely because it reads that class. Move it when the new home makes ownership and likely changes easier to understand.
Sources
- Martin Fowler — Move Function, also known as Move Method.