Every programming language embodies in it a philosophy about how problems should be solved. C reduces all problems to manipulations of memory addresses. Java turns every problem into a set of interacting objects. JavaScript summons Shub-Niggurath, the black goat of the woods with a thousand young, to eat the eyes of developers.
Just following the logic of a language can send you a long way to getting good results. Popular languages were designed by smart people, who work through many of the problems you might encounter when building a program with their tools. That doesn’t mean that you can’t take things a bit too far and misapply that philosophy, though.
Take this code, sent to us by “Kogad”. Their co-worker understood that objects and interfaces were fundamental to Java programming, so when presented with the challenge of three conditional statements, they created this:
package com.initrode.account.framework.process.specification;
import com.initrode.account.framework.process.CustomerRequest;
public interface ProcesSpecification {
boolean isSatisfiedBy(CustomerRequest req);
}
//--------------
package com.initrode.account.framework.process.specification;
public abstract class CompositeProcesSpecification implements ProcesSpecification {
public ProcesSpecification and(ProcesSpecification specification){
return new AndProcesSpecification(this, specification);
}
public ProcesSpecification or(ProcesSpecification specification){
return new OrProcesSpecification(this, specification);
}
public ProcesSpecification not(ProcesSpecification specification){
return new NotProcesSpecification(specification);
}
}
//--------------
package com.initrode.account.framework.process.specification;
import com.initrode.account.framework.process.CustomerRequest;
public class NotProcesSpecification extends CompositeProcesSpecification {
private ProcesSpecification spec;
public NotProcesSpecification(ProcesSpecification specification) {
spec = specification;
}
@Override
public boolean isSatisfiedBy(CustomerRequest req) {
return !spec.isSatisfiedBy(req);
}
}
//--------------
package com.initrode.account.framework.process.specification;
import com.initrode.account.framework.process.CustomerRequest;
public class AndProcesSpecification extends CompositeProcesSpecification {
private ProcesSpecification specOne;
private ProcesSpecification specTwo;
public AndProcesSpecification(ProcesSpecification specificationOne, ProcesSpecification specificationTwo) {
specOne = specificationOne;
specTwo = specificationTwo;
}
@Override
public boolean isSatisfiedBy(CustomerRequest req) {
return specOne.isSatisfiedBy(req) && specTwo.isSatisfiedBy(req);
}
}
//--------------
package com.initrode.account.framework.process.specification;
import com.initrode.account.framework.process.CustomerRequest;
public class OrProcesSpecification extends CompositeProcesSpecification {
private ProcesSpecification specOne;
private ProcesSpecification specTwo;
public OrProcesSpecification(ProcesSpecification specificationOne, ProcesSpecification specificationTwo) {
specOne = specificationOne;
specTwo = specificationTwo;
}
@Override
public boolean isSatisfiedBy(CustomerRequest req) {
return specOne.isSatisfiedBy(req) || specTwo.isSatisfiedBy(req);
}
}
//--------------
package com.initrode.account.framework.process.specification;
import com.initrode.account.framework.process.CustomerRequest;
import com.initrode.account.framework.process.CustomerType;
public class TypeOneProcesSpecification extends CompositeProcesSpecification {
@Override
public boolean isSatisfiedBy(CustomerRequest req) {
return null != req && CustomerType.ONE == req.getType();
}
}
//--------------
package com.initrode.account.framework.process.specification;
import com.initrode.account.framework.process.CustomerRequest;
import com.initrode.account.framework.process.CustomerType;
public class TypeTwoProcesSpecification extends CompositeProcesSpecification {
@Override
public boolean isSatisfiedBy(CustomerRequest req) {
return null != req && CustomerType.TWO == req.getType();
}
}
//--------------
package com.initrode.account.framework.process.specification;
import com.initrode.account.framework.process.CustomerRequest;
public class VerifyProcessSpecification extends CompositeSpecification
@Override
public boolean isSatisfiedBy(CustomerRequest req) {
return req.hasVerificationCode();
}
}
//--------------
// Usage:
public class ActionOne {
private ProcesSpecification procesSpec;
@PostConstruct
protected void postInitialize() {
setProcesSpecification(new VerifyProcessSpecification().and(new TypeOneProcesSpecification()));
}
@Override public boolean canHandle(CustomerRequest req) {
return procesSpec.isSatisfiedBy(req);
}
@Override
void doAction(...);
}
public class ActionTwo {
private ProcesSpecification procesSpec;
@PostConstruct
protected void postInitialize() {
setProcesSpecification(new VerifyProcessSpecification().and(new TypeTwoProcesSpecification()));
}
@Override public boolean canHandle(CustomerRequest req) {
return procesSpec.isSatisfiedBy(req);
}
@Override
void doAction(...);
}
public class ActionThree {
private ProcesSpecification procesSpec;
@PostConstruct
public void postInitialize() {
procesSpec = new NotProcesSpecification(new VerifyProcessSpecification().and(
new TypeOneProcesSpecification().or(new TypeTwoProcesSpecification())));
}
@Override public boolean canHandle(CustomerRequest req) {
return procesSpec.isSatisfiedBy(req);
}
@Override
void doAction(...);
}
This is certainly Peak Java™. It’s… extensible, at least. Not that you’d want to. “Kogad” replaced this masterpiece with a much simpler, if less extensible, chain of conditionals that were also more closely mapped to their actual requirements.