简体   繁体   中英

Invoke concrete class functions through common interface

I have the following concrete classes that implement a common interface

EvaluatorA : IEvaluator
EvaluatorB : IEvaluator
EvaluatorC : IEvaluator

The interface IEvaluator has only one function - Evaluate , which is implemented in all three types of evaluators. And I have a driver class that invokes an evaluator based on configuration, however, it is only having access (by design) to IEvalutor , ie, it does not need to know which concrete evaluator is currently being invoked.

The problem arises when one of the evaluators, say EvaluatorC , needs to implement a new function Predict , and my requirement is only for EvaluatorC , the Predict function needs to be called after calling Evaluate .

Temporal solution 1: One solution is to check the evaluator type:

// evaluator is previously instanciated
evaluator.Evaluate();
if (evaluator is EvaluatorC)
    evaluator.Predict();

As you could see, this is not neat. Say tomorrow I need to call another function Dance for only EvaluatorB and function Sing for both EvaluatorA and EvaluatorB , it becomes messy.

Temporal solution 2: Add function Predict to the interface IEvaluator , and for other evaluators, just implement the function with an empty body. This could work for void return type functions, but it needs additional safety check in the driver program if the return type is not void . In addition, I am not sure if having a function with empty body only as placeholders is a good idea or not.

Temporal solution 3: Change the interface to an abstract class. This is similar to solution 2, but provides a default implementation of Predict . However, I did not like this approach either as it alters the original structure of the project and does not bring many benefits compared to solution 2.

Overall, I do not have a satisfying solution to this problem. I am hoping that decoration pattern could help (but I am not sure). This problem is not specific to any programming languages. Please jump in and share your ideas.

Edit 1: Added some details about Evaluator responsibilities Evalutors are supposed to evaluate a given solution and return some metrics. After getting the evaluation metrics, driver program will do some housekeeping task, such as reporting, note that this is needed for all evaluators. And then one of the evaluators ( EvaluatorC ) needs to call Predict() based on the generated reports. However, the other evaluators do not require this step.

Since we're talking about design patterns, I think what you're describing brings to mind the template method pattern .

The essence is that you define the skeleton of your algorithm in an base class and let subclasses choose whether they want to implement certain steps or not. Here's an example.

abstract class EvaluatorPredictor {
  void evaluateAndPredict() {
    evaluate();
    predict();
  }

  protected void evaluate() {
    // no-op
  };

  protected void predict() {
    // no-op
  };
}

class AEvaluator extends EvaluatorPredictor {
  protected void evaluate() {
    System.out.println("I implement this");
  }
}

class BEvaluator extends EvaluatorPredictor {
  protected void evaluate() {
    System.out.println("I implement this");
  }


  protected void predict() {
    System.out.println("I implement this too");
  }
}

Please note that you can get more power with composition. For example the EvaluatorPredictor , or any class for that matter, could use two objects that implement an Evaluator and Predictor interface respectively.

class Whatever {
  constructor(e Evaluator, p Predictor) {
    this.e = e;
    this.p = p;
  }

  void evaluateAndPredict() {
    this.e.evaluate();
    this.p.predict();
  }
}

PS. Excuse my poor Java-like syntax. I'm sure there are errors in method declarations or access modifiers. Hope the above helps though.

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