Refactoring: Refactorings/Move Method

From Notes
Jump to navigation Jump to search

If a method is using (or will be used) by more features of another class than the one on which it is defined, then it should be moved into that class.

Mechanics

  1. Examine all features used by the source method that are defined on the source class. Consider whether they should be moved
    Note: If a feature is used only by the method you are about to move, you might as well move it too. If the feature is used by other methods, consider moving them as well. Sometimes it's easier to move a clutch of methods than to move them one at a time.
  2. Check the sub- and superclasses of the source class for overriding definitions of the method. (If there are other definitions, you may not be able to move unless polymorphism can also be expressed on the target.)
  3. Define the method in the target class. (Choose a more descriptive name if necessary)
  4. Copy the code from the source method to the target. Adjust the method to make it work in its new home.
    Note: If the method uses its source, try passing in the source object reference as a parameter
  5. Determine how to reference the correct target object from the source
  6. Turn the source method into a delegating method
  7. Test
  8. Decide whether to remove the source method or retain it as a delegating method. (leave as a delegating method if it has many references)
  9. If source method is removed, replace all of its references with references to the new target method
  10. Test

Example

Suppose there will be multiple types of accounts, each of which will have its own method of calculating overdraft charges. overdraft_charge should really be on the AccountType superclass.

Before

class Account
  def overdraft_charge
    if @account_type.premium?
      result = 10
      result += (@days_overdrawn - 7) * 0.85 if @days_overdrawn > 7
      result
    else
      @days_overdrawn * 1.75
    end
  end

  def bank_charge
    result = 4.5
    result += overdraft_charge if @days_overdrawn > 0
    result
  end
end

After

class AccountType
  def overdraft_charge(account)
    if premium?
      result = 10
      if account.days_overdrawn > 7
        result += (account.days_overdrawn - 7) * 0.85
      end
      result
    else
      account.days_overdrawn * 1.75
    end
  end
end

class Account
  def bank_charge
    result = 4.5
    if @days_overdrawn > 0
      result += @account_type.overdraft_charge(self)
    end
    result
  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