Tuesday, February 23, 2016

Refactoring - extract template method

Use this refactoring method when different classes have one method that is performing the same steps but each step is different.

We can create a common method (a template method that is) in the super class and define each step in each class

Let's consider the following example:


class Cube {
    var side:Float = 0
    
    func printDescription() {
        print("This is a cube")
        print("It has the side \(side)")
        print("It has the perimeter \(side*4)")
        print("It has the area \(side*side)")
    }
}

class Rectangle {

    var width:Float = 0
    var height:Float = 0
    
    func printDescription() {
        print("This is a rectangle")
        print("It has the width \(width) and height \(height)")
        print("It has the perimeter \((width+height)*2)")
        print("It has the area \(width*height)")
    }
}

Here is some test code:

let cube = Cube()
cube.side = 5
cube.printDescription()

let rectangle = Rectangle()

rectangle.width = 3
rectangle.height = 2
rectangle.printDescription()

The printDescription method is performing similar steps (print the type of class, the sides, the perimeter and the area) but each step is different.

In the superclass, we can extract a common method that performs the individual steps but define the steps in the subclass.

class Shape {
    func printDescription(){
        printShapeType()
        printSides()
        printPerimeter()
        printArea()
    }
    func printShapeType(){}
    func printSides() {}
    func printPerimeter(){}
    func printArea(){}
}

We can now remove printDescription from the subclasses, but override each individual step:

class Cube: Shape {
    var side:Float = 0
    override func printShapeType(){
        print("This is a cube")
    }
    override func printSides() {
        print("It has the side \(side)")
    }
    override func printPerimeter(){
        print("It has the perimeter \(side*4)")
    }
    override func printArea(){
        print("It has the area \(side*side)")
    }
}

class Rectangle : Shape {
    var width:Float = 0
    var height:Float = 0
    override func printShapeType(){
        print("This is a rectangle")
    }
    override func printSides() {
        print("It has the width \(width) and height \(height)")
    }
    override func printPerimeter(){
        print("It has the perimeter \((width+height)*2)")
    }
    override func printArea(){
        print("It has the area \(width*height)")
    }
}

If we have a different shape, in order to have printDescription working properly all we need to do is to implement each step.



No comments:

Post a Comment