Refactoring: Refactorings/Replace Method with Method Object

From Notes
Jump to navigation Jump to search

Turns a method into its own object so local variables become instance variables on that object. Code then becomes much easier to refactor in other ways.

Useful in a long method that uses local variables so you can't use Extract Method.

Mechanics

  1. Create a new class. Name it after the method
  2. Give the new class an attribute for the object that once hosted the original method (source object), and an attribute for temporary variables and parameters in the method
  3. Give the new class a constructor that takes the source object and each parameter
  4. Give the new class a method named "compute"
  5. Copy the body of the original method into compute, using the source object instance variable for any reference to methods on the source object
  6. Test
  7. Replace old method with one that creates new object and calls compute.


Example

Before

class Account
  def gamma(input_val, quantity, year_to_date)
    important_value1 = (input_val * quantity) + delta
    important_value2 = (input_val * year_to_date) + 100
    if (year_to_date - important_value1) > 100
      important_value2 -= 20
    end
    important_value3 = important_value2 * 7
    # ...
    important_value3 - 2 * important_value1
  end
end

After

class Gamma
  attr_reader :account, :input_val, :quantity, :year_to_date, :important_value1, :important_value2, :important_value3

  def initialize(account, input_val_arg, quantity_arg, year_to_date_arg)
    @account = account
    @input_val = input_val_arg
    @quantity = quantity_arg
    @year_to_date = year_to_date_arg
  end

  def compute
    @important_value1 = (input_val * quantity) + @account.delta
    @important_value2 = (input_val * year_to_date) + 100
    if (year_to_date - important_value1) > 100     # now we could easily Extract Method on this
      @important_value2 -= 20
    end
    @important_value3 = important_value2 * 7
    # ...
    @important_value3 - 2 * important_value1
  end
end

class Account
  def gamma(input_val, quantity, year_to_date)
    Gamma.new(self, input_val, quantity, year_to_date).compute
  end
end
Refactorings
Composing Methods

Extract MethodInline MethodInline TempReplace Temp with QueryReplace Temp with ChainIntroduce Explaining VariableSplit Temporary VariableRemove Assignments to ParametersReplace Method with Method ObjectSubstitute AlgorithmReplace Loop with Collection Closure MethodExtract Surrounding MethodIntroduce Class AnnotationIntroduce Named ParameterRemove Named ParameterRemove Unused Default ParameterDynamic Method DefinitionReplace Dynamic Receptor with Dynamic Method DefinitionIsolate Dynamic ReceptorMove Eval from Runtime to Parse Time

Moving Features Between Objects

Move MethodMove FieldExtract ClassInline ClassHide DelegateRemove Middle Man

Organizing Data

Self Encapsulate FieldReplace Data Value with ObjectChange Value to ReferenceChange Reference to ValueReplace Array with ObjectReplace Hash with ObjectChange Unidirectional Association to BidirectionalChange Bidirectional Association to UnidirectionalReplace Magic Number with Symbolic ContentEncapsulate CollectionReplace Record with Data ClassReplace Type Code with PolymorphismReplace Type Code with Module ExtensionReplace Type Code with State-StrategyReplace Subclass with FieldsLazily Initialized AtributeEagerly Initialized Attribute

Simplifying Conditional Expressions

Decompose ConditionalRecompose ConditionalConsolidate Conditional ExpressionConsolidate Duplicate Conditional FragmentsRemove Control FlagReplace Nested Conditional with Guard ClausesReplace Conditional with PolymorphismIntroduce Null ObjectIntroduce Assertion

Making Method Calls Simpler

Rename MethodAdd ParameterRemove ParameterSeparate Query from ModifierParameterize MethodReplace Parameter with Explicit MethodsPreserve Whole ObjectReplace Parameter with MethodIntroduce Parameter ObjectRemove Setting MethodHide MethodReplace Constructor with Factory MethodReplace Error Code with ExceptionReplace Exception with TestIntroduce GatewayIntroduce Expression Builder

Dealing with Generalization

Pull Up MethodPush Down MethodExtract ModuleInline ModuleExtract SubclassIntroduce InheritanceCollapse HierarchyForm Template MethodReplace Inheritance with DelegationReplace Delegation with HierarchyReplace Abstract Superclass with Module

Big Refactorings

Tease Apart InheritanceConvert Procedural Design to ObjectsSeparate Domain from PresentationExtract Hierarchy