Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a name for this Design Pattern? (Base class with implementations that only invoke constructor)

Edit: I've realised that this pattern feels a lot like currying, a technique that functional programmers use to specify function parameters in advance of invocation. The difference here is that we're currying constructors on objects instead of simply currying functions.


Throughout a couple of projects I've found myself using this bizarre design pattern that I can't find the name of. Does it have a name? Perhaps it's just bad practice, you tell me.

The Design Pattern

With this pattern, you would have...

  1. An abstract base class without abstract methods (we can discuss this later).
  2. Many "implementations" of the base class. However, these implementations would only serve to invoke the constructor of the base class.

A Java Example (with hypothetical scenario)

I will define a hypothetical scenario to provide some context.

Scenario:

Bob is writing a small API for scanning source code. He wants to be able to check if a comment starts/ends at a given index within the source code.

Here is Bob's code.

1. The Abstract Base Class

public abstract class CommentDetector {

    private final String startPattern;
    private final String endPattern;

    protected CommentDetector(String startPattern, String endPattern) {
        this.startPattern = startPattern;
        this.endPattern = endPattern;
    }

    public boolean commentStartsAt(int index, String sourceCode) {
        // ...
    }

    public boolean commentEndsAt(int index, String sourceCode) {
        // ...
    }

}

You may be wondering why it is abstract but has no abstract methods. This is simply because Bob doesn't want you to instantiate it directly. Bob wants you to write an implementation of CommentDetector and then instantiate that instead. Here are two of Bob's implementations...

2. Some Implementations

One for multi-line comments in Java:

public class JavaMultiLineCommentDetector extends CommentDetector {

    public JavaMultiLineCommentDetector() {
        super("/*", "*/");
    }
}

One for single-line comments in Java:

public class JavaSingleLineCommentDetector extends CommentDetector {

    public JavaSingleLineCommentDetector() {
        super("//", "\n");
    }
}

Bob has written these implementations for us so that we can write new JavaMultiLineCommentDetector() instead of new CommentDetector("/*", "*/").

Bob also encourages you to write your own implementations for other languages if need be.


Summary

  • It feels like the intent of this design pattern is to improve readability of the code by pre-defining constructor calls.

  • This design pattern gives a polymorphic feel to the code (even though it may/may not be truly polymorphic).

  • Writing new implementations is quick and easy.

  • Implementations do not depend on each other, and can be compiled/deployed independently.

Does this design pattern have a name?

like image 430
byxor Avatar asked Oct 29 '22 21:10

byxor


2 Answers

With the extensible enum pattern (already noted in comments) you can also avoid the inheritance:

public interface CommentDelimiter {
    String getStartPattern();
    String getEndPattern();
}

public interface CommentDetector {
    boolean commentStartsAt(int index, String sourceCode);
    boolean commentEndsAt(int index, String sourceCode);
}

public enum CommentDetectors implements CommentDetector {
    JAVA_MULTILINE(CommentDelimiters.JAVA_MULTILINE),
    JAVA_SINGLELINE(CommentDelimiters.JAVA_SINGLELINE);

    // ... store commentDelimiter

    public boolean commentStartsAt(int index, String sourceCode) {
        // ... using commentDelimiter.getStartPattern()
    }

    public boolean commentEndsAt(int index, String sourceCode) {
        // ... using commentDelimiter.getEndPattern()
    }
}

public enum CommentDelimiters implements CommentDelimiter {
    JAVA_MULTILINE("/*", "*/"),
    JAVA_SINGLELINE("//", "\n");

    // ... store start, end
}
like image 61
charlie Avatar answered Nov 17 '22 08:11

charlie


It feels like the intent of this design pattern is to improve readability of the code by pre-defining constructor calls.

In OOP, constructors should not be used to define contract since :

  • it is less precise than a abstract method
  • concrete classes may misused the super constructor
  • it is not designed for being extensible in a OOP way since it doesn't allow the overriding of behavior.

Generally, the Factory method or the builder Design Patterns are more commonly used when you want allow to your class clients to choose what object must be used in a processing :

Abstract class :

public abstract class CommentDetector {

  private final String startPattern;
  private final String endPattern;

  public abstract String getStartPattern();
  public abstract String getEndPattern();

  public boolean commentStartsAt(int index, String sourceCode){        
      getStartPattern()...
  }

  public boolean commentEndsAt(int index, String sourceCode){
      getEndPattern()....
}

Concrete class

public class JavaSingleLineCommentDetector extends CommentDetector {

     public String getStartPattern(){
         return "//";
     }

     public abstract String getEndPattern(){
         return "\n";
     }
}

This design pattern gives a polymorphic feel to the code (even though it may/may not be truly polymorphic).

Writing new implementations is quick and easy.

It's true in this case since the class becomes extensible. You can use a concrete class and override any factory method if you want.

like image 45
davidxxx Avatar answered Nov 17 '22 09:11

davidxxx