CSC/ECE 517 Fall 2010/ch7 7f LG

From Expertiza_Wiki
Jump to navigation Jump to search

Call super Anti-Pattern

Introduction

Having to call super when inheriting from a super-class is considered an anti-pattern or code smell. Whenever you have to remember to do something besides inheriting the method every time, chances are that you will forget it and this is a sign of a bad API. We can solve this by defining a public method that does the housekeeping and calls a second method, often called the hook, which the subclass has to override. Following this refactor will strengthen the API by alleviating the programmer from remembering to call super each time.

Description

It is not the need to perform an action on the super class, but the requirement of calling the parent what we considered an anti-pattern. An API following the call super anti-pattern relies on the user to make the call, hence malfunctioning whenever the user forgets to add the call to his/her subclassed method.

Adding a hook is not always possible; the source code of the parent class might not be available in a closed/black-box API. This is not the only problem inheriting closed API classes; the user must keep an eye on the changes done in the class by the developer because it might break the subclass. A possible solution to the black-box class is languages’ annotation capabilities.

Example

The following example is inspired in both the Wikipedia [1] and Martin Fowler’s [2] examples. By design, each subclass of vehicle should call super when overriding MoveForward and then perform their specific behavior. The programmer must remember to do so, if he does not, the vehicle will not move.

public class Vehicle {
	...
	public void MoveForward() {
		// Housekeeping
		ValidateMove();
		UpdateDisplay(POSITION);
		...
	}
	...
}
public class Car : Vehicle {
	...
	public void MoveForward() {
		base.MoveForward();
		UpdateDisplay(WHEEL_MARKS); // Do Car-specific actions
	}
	...
}

Following the solution proposed in Martin Fowler’s article [2], we refactor this code adding a hook called AfterMoveForward, which is the method the subclasses must override. Whenever we call MoveForward within a Car object, the appropriate movement and car-specific action will be performed.

public class Vehicle {
	...
	public void MoveForward() {
		// Housekeeping
		ValidateMove();
		UpdateDisplay(POSITION);
		...
		AfterMoveForward();
	}
	protected abstract void AfterMoveForward();
	...
}
public class Car : Vehicle {
	...
	public void AfterMoveForward() {
		UpdateDisplay(WHEEL_MARKS); // Do Car-specific actions
	}
	...
}

A visual representation of the calls is shown, it follows the structure of the Wikipedia [1] example.

Real World Examples

Ruby on Rails

Refactoring Rails 1.x tests to work with Rails 2.x might require the use of the call super anti-pattern. Michael Koziarski points out that functional tests inheriting ActiveSupport::TestCase that define a custom setup method must call super in Rails 2.x [3]. A custom setup is one that does something else besides defining @controller, @request and @response.

class xControllerTest < ActionController::TestCase
	def setup
		super
		...
	end
	...
end

References

[1] Wikipedia. (2010, December) Wikipedia - Call super. [Online]. http://en.wikipedia.org/wiki/Call_super

[2] Martin Fowler. (2010, December) Martin Fowler. [Online]. http://martinfowler.com/bliki/CallSuper.html

[3] Michael Koziarski. (2007, December) redemption in a blog. [Online]. http://blog.codefront.net/2007/12/27/dry-in-your-functional-and-actionmailer-tests-rails-20-a-feature-a-day-7/