Monday, August 24, 2015

Strategy pattern for modularization

When your software exceeds a certain size, it's a good idea to separate it into modules that can be compiled and tested independently (for example, it is easier to isolate memory leak causes). Some modules might also have value as standalone components.


One problem is the module's dependency on other libraries. During tests you don't always need the full libraries and could be satisfied with simpler ones that you can quickly write.


For example, your module might be calling an external method that calculates the constant Pi. The real library might implement this method using many significant digits. But since most of your module tests won't be about accuracy, a less accurate Pi will suffice. Note that accuracy tests should be performed on the library itself, not on the module calling the lib.

What you need is to separate the interface of Pi calculation method from its implementation. Then you can provide a simpler version for standalone testing and the real version when the module is integrated into the system. This design is an application of the Strategy Pattern (selecting an algorithm at runtime).

package modules;
public interface PiCalc {
    public double calcPi();
}
package modules;
public class RealPi implements PiCalc {
    @Override
    public double calcPi() {
        return Math.PI;
    }    
}
package modules;
public class SimplePi implements PiCalc {
    @Override
    public double calcPi() {
        return 3.14;
    }    
}
package modules;
public class Module1 {    
    private final PiCalc pc;
    public Module1(PiCalc pc) {
        this.pc = pc;
    }    
    public double calcPi() {
        return pc.calcPi();
    }    
}
package modules;
/**
 * Tests Module1 with a simple implementation of Pi.
 *
 * @author skorkmaz
 */
public class Module1Tester {    
    public static void main(String[] args) {
        Module1 m1 = new Module1(new SimplePi());
        System.out.println("Simple pi = " + m1.calcPi());
    }
}
package modules;
/**
 * Module1 with a real implementation of Pi.
 *
 * @author skorkmaz
 */
public class SoftwareSystem {    
    public static void main(String[] args) {
        Module1 m1 = new Module1(new RealPi());
        System.out.println("Real pi = " + m1.calcPi());
    }
}

No comments: