Refactoring 101: Replace Method with Method Object

Daniel Lozano Valdés
2 min readOct 16, 2015

--

For the third part of this series of micro posts on refactoring I would like to talk about another simple (aren’t they all?) refactoring that I just had to use a couple of days ago.

This refactoring does exactly what its name implies. It replaces a long and difficult to understand method and places it in it’s own class. The multitude of local variables that you probably have lying around in that method then become instance variables on the new class.

Afterwards, you probably want to go further and decompose that long method into smaller methods (we should always have small methods) in the new class. This should be easy, since all our local variables are now instance variables, you don’t have to worry about passing a ton of parameters around.

For example, say we have this method in Swift: (This code was shortened and edited for clarity, it was even longer than this.)

func imageFromCurrentFilterChain() -> NSImage?
{
var filterChain: [GPUImageFilter] = [] var inputGPUImage = GPUImagePicture(...)
var lutImage = GPUImagePicture(...)
var grayColor = GPUSolidColorGenerator(...)
var grainImage = GPUImagePicture(...)
if filterChain.count == 0 && !applyBlur{
return input?.displaySizeImage
}
inputGPUImage?.removeAllTargets()
lutImage?.removeAllTargets()
grayColor.removeAllTargets()
...
if !filterChain.isEmpty{
inputGPUImage!.addTarget(filterChain.first)
}
var previousFilter : GPUImageFilter? for (index, filter) in filterChain.enumerate(){

filter.removeAllTargets()
if index != 0{
previousFilter?.addTarget(filter)
}
if filter is GPUImageLookupFilter{
lutImage = GPUImagePicture(...)
lutImage?.addTarget(filter)
}else if filter is GPUImageLightenBlendFilter{
grayColor.addTarget(filter)
grayColor.setColorRed(...)
grayColor.forceProcessingAtSize((inputImage?.size)!)
}else if filter is GPUImageOverlayBlendFilter{
grainImage.addTarget(filter)
}
previousFilter = filter

...
}

You should never have huge methods like this! All of that could become a new class called FilterChain with an interface sort of like this: (Pseudocode)

class FilterChain{  instance var filterChain
instance var lookupFilter
instance var lutImage
instance var grayColor
instance var grayImage
initWithArray(Array){
...
}
removeAllTargets(){
...
}
setupLookupFilter(){
...
}
setupLightenBlendFilter(){
...
}
public imageFromCurrentFilterChain(){
...
}
}

Then, your old method would look like this:

func imageFromCurrentFilterChain() -> {
return filterChain.imageFromCurrentFilterChain()
}

This makes each class have it’s own specific responsibility, and now you can reuse the FilterChain class other parts of your code or different projects.

--

--