Is there a name for this design pattern? (Base class with implementations that call only the constructor)

Edit: I realized that this pattern is very similar to currying , a method that functional programmers use to indicate the function of parameters before calling. The difference here is that we create constructors for objects instead of simple currying functions.


Over the course of several projects, I found myself using this fancy design pattern that I cannot find. Does he have a name? Maybe this is just bad practice, tell me.

Design Pattern

With this template, you would ...

  • An abstract abstract class without abstract methods (we can discuss this later).
  • A lot of "implementations" of the base class. However, these implementations will only be used to invoke the base class constructor .

Java example (with a hypothetical scenario)

I am defining a hypothetical scenario to provide some context.

Scenario:

Bob writes a small API for scanning source code. He wants to check if a comment begins or ends with a given index in the source code.

Here is Bob's code.

1. 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 might be wondering why it is abstract, but does not have abstract methods. This is simply because Bob does not want you to instantiate it directly. Bob wants you to CommentDetector implementation, and then instantiate it 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 wrote these implementations for us so that we could write new JavaMultiLineCommentDetector() instead of new CommentDetector("/*", "*/") .

Bob also recommends that you write your own implementations for other languages, if necessary.


Summary

  • It seems that the purpose of this design pattern is to improve code readability by predefining constructor calls.

  • This design pattern provides a polymorphic view of the code (although it may not be truly polymorphic).

  • Writing new implementations is quick and easy.

  • Implementations are independent of each other and can be compiled / deployed independently.

Does this design template have a name?

+5
source share
3 answers

With the extensible enum template (already noted in the comments) you can also avoid 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 } 
+1
source

It seems that the purpose of this design pattern is to improve code readability by predefining constructor calls.

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

  • less accurate than abstract method
  • specific classes may misuse the superstructor
  • it is not intended to be expanded in OOP because it does not allow overriding behavior.

Typically, the Factory method or builder design patterns are more often used when you want your class clients to choose which object to use when 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 grade

 public class JavaSingleLineCommentDetector extends CommentDetector { public String getStartPattern(){ return "//"; } public abstract String getEndPattern(){ return "\n"; } } 

This design pattern gives a polymorphic view of the code (although it may / may not be truly polymorphic).

Writing new implementations is quick and easy.

This is true in this case, as the class becomes extensible. You can use a specific class and override any Factory method if you want.

+1
source

What is wrong with the Factory Method Template?

 public class CommentDetector { //... private CommentDetector(String startPattern, String endPattern) { this.startPattern = startPattern; this.endPattern = endPattern; } public static CommentDetector giveMeThisInstance() { return new CommentDetector("//", "\n"); } public static CommentDetector giveMeThatInstance() { return new CommentDetector("/*", "*/"); } } 

This approach will save your permgen memory. And for my subjective point of view, it is more consistent: save everything as a separate class, but create objects with different properties.

0
source

All Articles