content: // ───────────────────────────────────────────────────────────
  // 1. Base class defining the template method
  // ───────────────────────────────────────────────────────────
  abstract class ModelTrainer {
      // The template method — final so subclasses can’t change the sequence
      public final void trainPipeline(String dataPath) {
          loadData(dataPath);
          preprocessData();
          trainModel();      // subclass-specific
          evaluateModel();   // subclass-specific
          saveModel();       // subclass-specific or default
      }
  
      protected void loadData(String path) {
          System.out.println("[Common] Loading dataset from " + path);
          // e.g., read CSV, images, etc.
      }
  
      protected void preprocessData() {
          System.out.println("[Common] Splitting into train/test and normalizing");
      }
  
      protected abstract void trainModel();
      protected abstract void evaluateModel();
  
      // Provide a default save, but subclasses can override if needed
      protected void saveModel() {
          System.out.println("[Common] Saving model to disk as default format");
      }
  }
  
  // ───────────────────────────────────────────────────────────
  // 2. Concrete subclass: Neural Network
  // ───────────────────────────────────────────────────────────
  class NeuralNetworkTrainer extends ModelTrainer {
      @Override
      protected void trainModel() {
          System.out.println("[NeuralNet] Training Neural Network for 100 epochs");
          // pseudo-code: forward/backward passes, gradient descent...
      }
  
      @Override
      protected void evaluateModel() {
          System.out.println("[NeuralNet] Evaluating accuracy and loss on validation set");
      }
  
      @Override
      protected void saveModel() {
          System.out.println("[NeuralNet] Serializing network weights to .h5 file");
      }
  }
  
  // ───────────────────────────────────────────────────────────
  // 3. Concrete subclass: Decision Tree
  // ───────────────────────────────────────────────────────────
  class DecisionTreeTrainer extends ModelTrainer {
      // Use the default preprocessData() (train/test split + normalize)
  
      @Override
      protected void trainModel() {
          System.out.println("[DecisionTree] Building decision tree with max_depth=5");
          // pseudo-code: recursive splitting on features...
      }
  
      @Override
      protected void evaluateModel() {
          System.out.println("[DecisionTree] Computing classification report (precision/recall)");
      }
      // use the default saveModel()
  }
  
  // ───────────────────────────────────────────────────────────
  // 4. Usage
  // ───────────────────────────────────────────────────────────
  public class TemplateMethodPattern {
      public static void main(String[] args) {
          System.out.println("=== Neural Network Training ===");
          ModelTrainer nnTrainer = new NeuralNetworkTrainer();
          nnTrainer.trainPipeline("data/images/");
  
          System.out.println("\n=== Decision Tree Training ===");
          ModelTrainer dtTrainer = new DecisionTreeTrainer();
          dtTrainer.trainPipeline("data/iris.csv");
      }
  }
  