Design Mode--Template Mode

Posted by fareforce on Tue, 26 Oct 2021 18:27:17 +0200

Design Mode - Template Mode

  1. Points of knowledge involved

    • Java interfaces and abstract class information

      • One class can inherit only another class, but can implement multiple interfaces

      • Attributes can be defined in abstract classes, and attributes in interfaces are defined as public final static modifiers and are constants

      • Both interfaces and abstract classes can implement logic, interfaces are implemented by default modifiers, and abstract classes are implemented by common methods

      • Methods in interfaces are modified to public abstract by default

      • Abstract methods must be overridden in subclasses

      • - supplemented by others

        • Abstract classes cannot be new because abstract methods are not implemented. Interfaces are the same

        • The abstract class is public by default, and can be decorated with public and protected

        • Interfaces cannot contain static code blocks and static methods, but abstract classes can contain

        • At the design level, interfaces are abstractions of behavior, while abstract classes are abstractions of a unified type of thing (examples of birds and airplanes)

        • An Abstract class, as the parent of many subclasses, is a template design. The interface defines a behavior specification, a radiation class design. The function of an interface is to add a common method to a subclass without modifying it. An interface cannot be implemented.

        • Examples of implementation of door and warning functions. The open() and close() attributes of the door are inherent functions, and alarm() is additional functions. So try the following

          public abstract class Door{
            void open();
            void close();
          }
          
          public interface Alarm{
            void alarm();
          }
          
          public class AlarmDoor extends Door implements Alarm{
            void open();
            void close();
            void alarm();
          }
          
    • Method of default modification

      In JDK 1.8, default modifiers were added to the interface, acting like common methods in abstract classes. Modify the public method of the interface without modifying the subclass implementation. It's a solution to a legacy problem.

      Call method, which can call default-modified methods in an interface just like a normal parent method

      • If default modifies the same method in multiple interfaces, the class implementing the interface must override the default modifier in the interface
      • If both the interface and the parent have the same methods, and the interface is decorated with default, then the method in the parent will be used when the subclass is called
      • The interface default method enhances the Collections API in Java 8 to support lambda expressions.

      Use static code block static in interface

      • Cannot be replicated
      • Called by interface name.function()
    • Generic T E? Differences between

      Generics introduced in JDK 5 are essentially parameterized types. If you do not use generics, using Object will make parameters arbitrary, and the result of that arbitration will be determined at run time for the type conversion, which may fail. There is also a need to force type conversion within the code.

      T E K V? They are wildcards, and generally have the following semantics

      • T type E element K key v value
      • What? Indicates an indeterminate java type

      Wildcards of generic and indeterminate types need to be described separately

    • for(; 😉 Usage not found

    • Meaning of Obejct...

      Variable parameters in Java

      • Variable parameters must be placed last, so a method can only have one variable parameter
      • Variable parameters are essentially arrays
      • Variable parameters themselves are syntax sugars that are used extensively in python and can be used when parameter length is uncertain
    • Meaning of protected

      As a modifier of permission access control in java

      Access control boundaries are

      • All public classes are available
      • The producted subclass can access prodected-modified variables or methods, or classes under the same package can call
      • Default package-based access
      • private can only use variables or methods with the current class
  2. Functions of template methods

    Defines the skeleton of an algorithm in an operation, delaying some steps to a subclass. Template methods allow subclasses to redefine certain steps of the algorithm without changing the structure of an algorithm.

    Personal understanding: The template method is to write some action s, common parts in the abstract class of the parent class, and separate parts of each subclass in each subclass. Schemas that reduce unnecessary duplication and decoupling

    Template patterns are what we do if we look at programming as increasing scalability and calling modification complexity.

  3. Example 1, AbstrictList class in JDK uses template method, the code here is a bit strange. In AbstrictList, add(int index, E e) does not use abstract method, but subclass override method is also required

    public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
    		public boolean add(E e) {
            add(size(), e);
            return true;
        }
        
        /** In the AbstrictList, add (int index, E) is not used; instead, the method is defined as an abstract method and an exception is thrown. The effect of this is that
         *  In a subclass, the compiler has no exceptions if the method is not overridden, but an exception is thrown when the parent method is called.
         *  Therefore, subclasses must override this method to implement their own add logic
         */
        public void add(int index, E element) {
            throw new UnsupportedOperationException();
        }
    }
    
    // In the subclass ArrayList, the add (int index, E) method is overridden
    public class ArrayList<E> extends AbstractList<E>
            implements List<E>, RandomAccess, Cloneable, java.io.Serializable{
      
      public void add(int index, E element) {
            rangeCheckForAdd(index);
    
            ensureCapacityInternal(size + 1);  // Increments modCount!!
            System.arraycopy(elementData, index, elementData, index + 1,
                             size - index);
            elementData[index] = element;
            size++;
        }
    }
    
  4. The second example is encountered in the work. The requirement is to be a hybrid engine scheduler, which can select multiple engines to execute when executing SQL, and use other engines to downgrade when execution of the preferred engine fails.

    The idea with the template approach is that each engine executes code with roughly the same logic, such as cleaning up files ahead of time, checking execution results, and so on. But the specific execution, each engine department does not want to.

    • Abstract parent of engine

      public abstract class Engine {
      
          private List<CheckRule> rules;
          private String engineName;
      
          public Engine(String engineName, List<CheckRule> rules) {
              this.rules = rules;
              this.engineName = engineName;
          }
      
          public String getEngineName(){return engineName;}
      
          public List<CheckRule> getRules() {
              return rules;
          }
      
      
          public boolean run(EngineDispatcher dispatcher, String sql, Properties config){
              System.out.println("dear , your task is running...");
              long startTime = System.currentTimeMillis();
              clearDatePath(config.getProperty("dataPath"));
              boolean result = runInternal(sql, config);
              long endTime = System.currentTimeMillis();
              if (! result){
                  return fallBack(dispatcher,config.getProperty("roiginsql"),config);
              }
              return result;
          }
      
          protected void clearDatePath(String dataPath) {
              File file = new File(dataPath);
              try {
                  if(file.exists()){
                      FileWriter fileWriter = new FileWriter(file);
                      fileWriter.write("");
                      fileWriter.flush();
                      fileWriter.close();
                  }
              } catch (IOException e) {
                  e.printStackTrace();
              }
          }
      
          protected abstract boolean fallBack(EngineDispatcher dispatcher, String roiginsql, Properties config);
      
          protected abstract boolean runInternal(String sql, Properties config);
      
          protected abstract void cancel(Properties config);
      
      }
      
      
      
      

      Implementation of Hiveserver2 Engine

      public class Hiveserver2Engine extends Engine {
      
          static final int DEFAULT_QUERERY_TIME_OUT = 10 * 1000;
          HiveStatement stmt = null;
          Connection conn = null;
          public Hiveserver2Engine(String engineName) {
              super(engineName);
          }
      
          @Override
          protected boolean fallBack(EngineDispatcher dispatcher, String roiginsql, Properties config) {
              return false;
          }
      
          @Override
          protected boolean runInternal(String sql, Properties config) {
              //Specific implementation logic
              return false;
          }
      
          @Override
          protected void cancel(Properties config) {
              
          }
      }
      

      Implementation of Presto

      public class PrestoJDBCEngine extends Engine {
      
          public PrestoJDBCEngine(String engineName) {
              super(engineName);
          }
      
          @Override
          protected boolean fallBack(EngineDispatcher dispatcher, String roiginsql, Properties config) {
             // Demotion required here
              return false;
          }
          @Override
          protected boolean runInternal(String sql, Properties config) {
              return runPresto(sql,config);
          }
          @Override
          protected void cancel(Properties config) {
              
          }
      
          private boolean runPresto(String sql , final Properties config){
              return false;
          }    
      }
      
      
      public class EngineDispatcher {
      
          public static final String HIVE_SERVER2 = "";
          public static final String PRESTO_JDBC = "";
      
          public static String DEFAULT_ENGINE = HIVE_CLI;
      
          public Map<String, Engine> engines = new LinkedHashMap<String, Engine>();
          private Engine runningEngine;
      
          public EngineDispatcher() {
              engines.put(PRESTO_JDBC, new PrestoJDBCEngine(PRESTO_JDBC));
              engines.put(HIVE_CLI,new HiveCliEngine(HIVE_CLI));
          }
      
          // Select the logic of the engine, there are a lot of conditional judgments here
          public Map<String,String> dispatch(String sql, Properties config){
              // Distribute and parse sql rules to determine the execution engine
          }
      
          private String dispatchInternal(HiveClient hiveClient,
                                          String selectSql, Properties config) throws SQLException, RuleCheckException, ExplainResultException {
          }
      
          public Engine getRunningEngine() {
              return runningEngine;
          }
      
          public void setRunningEngine(Engine runningEngine) {
              this.runningEngine = runningEngine;
          }
      }
      

      Real Call

      public class ExecuteSql {
      
        private static Properties config;
        private static EngineDispatcher dispatcher = new EngineDispatcher();
        private static String address = "";
        
        
        public static boolean executeSql() {
          // Returns engine information and corresponding SQL
          Map<String, String> engineInfo = dispatcher.dispatch(sql, config);
          String engineName = engineInfo.get("engine");
          String convertedSql = engineInfo.get("convertedsql");
          config.setProperty("comment", engineInfo.get("comment"));
          config.setProperty("convertedsql", convertedSql);
          if (engineName.equals(EngineDispatcher.NO_ENGINE)) {
            LOG.info("Engine Selection Failed,Termination of execution!");
            return false;
          }
          LOG.info("Automatic Routing Engine: " + engineName);
          dispatcher.setRunningEngine(dispatcher.engines.get(engineName));
          //Here is the actual call
          return dispatcher.getRunningEngine().run(dispatcher, convertedSql, config);
        }
        
      }
      

Reference connection:

https://segmentfault.com/a/1190000038823160

https://blog.csdn.net/wf13265/article/details/79363522

Topics: Java