简体   繁体   中英

Protected “stub” methods used only for overriding purposes considered good practice or not?

Sometimes when I extend one of my own classes, I want to (for the purpose of the subclass) "inject" one or two lines of code in the middle a method in the super class.

In these cases I sometimes add a call to an empty protected method for the subclass to override.

public void superClassMethod() {

    // some fairly long snippet of code

    doSubclassSpecificStuff();

    // some other fairly long snippet of code

}

// dummy method used for overriding purposes only!
protected void doSubclassSpecificStuff() {
}

When doing this several times in the same class I must say it looks quit awkward / ugly so my questions:

  1. Is this way of "opening up" for subclasses to "inject" code in the middle of methods considered good practice or not?
  2. Is the pattern (anti-pattern?) called something?
  3. Has it been used in any well known API / library? (Note that I'm talking about non-abstract classes.)
  4. Are there any better alternatives?

The only alternative I can come up with is to use something like the command pattern and have a setMiddleOfMethodHandler(SomeRunnableHandler) , and call handler.doSubclassSpecificStuff() instead of the dummy-method. It has a few drawbacks as I see it though, such as for instance not being able to touch protected data.

You've just discovered the Template method design pattern. Note though that normally the methods that comprise the individual steps are abstract (rather than empty and protected) so that subclasses must override them.

There is the Template method pattern . The idea there is that much of the work is common, except for a few bits, which are handled by a subclass implemented method.

Yes, this is a legitimate way to do things; I've used it myself.

The only problem I can see is not the specific technique, but the fact that you are using subclasses of concrete (read: non-abstract) classes at all. Subclassing concrete classes has many subtle problems, so I would recommend to avoid it altogether. See eg http://en.wikipedia.org/wiki/Liskov_substitution_principle for an explanation of what you must do to properly subclass a class, and the problems involved. Also, in "Effective Java" Block recommends using composition (Item 16).

Another approach (that avoids subclassing) would be to use Dependency Injection . Your method would accept a parameter of a type that implements the interface ISpecificStuff , which specifies a method doSubclassSpecificStuff() :

public void superClassMethod(ISpecificStuff specificStuff) {
  ....
  specificStuff.doSubclassSpecificStuff();
  ....
}

That way, any caller can decide what the method should do. This avoids the need for subclassing. Of course, you could inject via a constructor, if you need it in more than one method.

It looks fishy to me. I think the reason you're ending up having to do this is a design flaw. Your method that needs to be "split" probably does too much. The solution would be to break it up in steps, and give that "doSubclassSpecificStuff" step a specific meaning.

For ex.:

void Live()
{
  BeBorn();
  DoCrazyStuff(); // this can be made protected virtual
  Die();
}

Yes, it's perfectly fine. This is an example of the Template Method pattern, where you use inheritance to define a method that maintains a known "skeleton", but can have custom logic.

public abstract class Ancestor
{
   protected virtual void CanOverrideThisStep(){...}

   protected abstract void MustDefineThisStep();

   protected sealed void MustDoExactlyThis(){...}

   private void HideThisStepFromEveryone(){...}

   public sealed void TemplateMethod()
   {
      ...
      CanOverrideThisStep();

      ...
      MustDoExactlyThis();

      ...
      MustDefineThisStep();

      ...
      HideThisStepFromEveryone();
   }
}

Inheritors of Ancestor above must define a body for MustDefineThisStep(), and may at their option override CanOverrideThisStep(), but cannot touch MustDoExactlyThis(), HideThisStepFromEveryone, or the TemplateMethod driving function itself. However, except for HideThisStepFromEveryone, all the submethods are available to child classes, so a child may use MustDoExactlyThis() in the implementation of MustDefineThisStep().

This is very common; such constructions are the reason OO languages have such access modifiers such as these at their disposal. The pattern is very useful for workflows, file processing, and other tasks that are generally the same but have slightly different implementation details.

I routinely use this technique as a way to handle special cases. I'll write things like this:

public void foo()
{
  theData=getTheData();
  preprocessDataHook(theData);
  putTheData(theData);
}
protected void preprocessDataHook(SomeObject theData)
{
  // Nop. Available for subclasses to override.
}

A subclass that does not need to preprocess the data can then just not override this function. A subclass that does need to preprocess can override the function.

If we expected that all or most subclasses would need to preprocess, then this should be an abstract function to force the programmer to implement it, or make a conscious decision to do nothing. But if it's just an occassional subclass that needs to do something here, I think this is a perfectly valid approach.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM