I was looking for refactoring a too length method. Searching I found this technique: Replace Method with Method Object but I don't understand at all.
If the method to refactor is:
public class Order {
//Method to refactor
public double price() {
double primaryBasePrice;
double secondaryBasePrice;
double tertiaryBasePrice;
//compute impl
}
//.....
}
With the web example the refactor Replace Method with Method Object would be as next:
public class Order {
//Method refactored
public double price() {
return new PriceCalculator(this).compute();
}
//.......
}
//Method object
public class PriceCalculator {
private double primaryBasePrice;
private double secondaryBasePrice;
private double tertiaryBasePrice;
public PriceCalculator(Order order) {
//??
}
public double compute() {
// impl
}
}
But how PriceCalculator
gets primaryBasePrice
, secondaryBasePrice
, tertiaryBasePrice
values to do the compute?
I only see it is possible passing the values in the constructor as next:
//Method object
public class PriceCalculator {
private double primaryBasePrice;
private double secondaryBasePrice;
private double tertiaryBasePrice;
public PriceCalculator(Order order, double primaryBasePrice,
double secondaryBasePrice, double tertiaryBasePrice) {
this.primaryBasePrice = primaryBasePrice;
this.secondaryBasePrice = secondaryBasePrice;
this.tertiaryBasePrice = tertiaryBasePrice;
}
public double compute() {
// impl
}
}
Otherwise, why pass in the constructor order
instance reference? Why is needed?
Passing instance of order
:
return new PriceCalculator(this, primaryBasePrice, secondaryBasePrice, tertiaryBasePrice).compute();
Without order
instance reference:
return new PriceCalculator(primaryBasePrice, secondaryBasePrice, tertiaryBasePrice).compute();
But how PriceCalculator gets primaryBasePrice, secondaryBasePrice, tertiaryBasePrice values to do the compute?
The same way it was before refactoring.
If you look at the original code, primaryBasePrice
, secondaryBasePrice
and tertiaryBasePrice
are local variables, whose values are being set somewhere in the //compute impl
section.
public double price() {
double primaryBasePrice;
double secondaryBasePrice;
double tertiaryBasePrice;
// compute impl
// all base price variables are assigned somewhere in here
}
After refactoring, the compute()
method has a copy of the //compute impl
code, and simply assigns the exact same values to the fields in PriceCalculator
as it did to the local variables before refactoring.
We need to pass in a reference to the Order
object in case those values are dependent on its methods or internal state.
For instance, if we previously had
public double price() {
double primaryBasePrice;
double secondaryBasePrice;
double tertiaryBasePrice;
// some of compute impl
primaryBasePrice = getPrimary();
secondaryBasePrice = getSecondary();
tertiaryBasePrice = getTertiary();
// the rest of compute impl
}
after refactoring, we would instead have something like
public double compute() {
double primaryBasePrice;
double secondaryBasePrice;
double tertiaryBasePrice;
// some of compute impl
primaryBasePrice = order.getPrimary();
secondaryBasePrice = order.getSecondary();
tertiaryBasePrice = order.getTertiary();
// the rest of compute impl
}
So to answer both your questions:
But how PriceCalculator gets primaryBasePrice, secondaryBasePrice, tertiaryBasePrice values to do the compute?
. Yes, you are right, you need to send them as constructor parameters.
Otherwise, why pass in the constructor order instance reference? Why is needed?
You need to pass the order instance reference in order to be able to call other methods of Order. In the example you gave, it is a trivial method, but in some other methods you might be calling some of the Order's methods...
One problem with this refactoring technique is that if your original method accesses Order's private methods, then you'd have to either make them package protected or replicate those methods in the target Method Object...
And if you make those private methods as package protected, then you get tight coupling, feature envy and maybe other problems
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With