zoukankan      html  css  js  c++  java
  • Effective Java 34 Emulate extensible enums with interfaces

      

    Advantage

    Disadvantage

    Enum types

    Clarity

    Safety

    Ease of maintenance.

    None extensibility

    Typesafe enum pattern(Interfaces to emulate extensible enums)

    Extensibility

    No good way to enumerate all of the elements of a base type and its extension.

    Extensibility would complicate many aspects of the design and implementation.

    Implementations cannot be inherited from one enum type to another.

       

    Scenario

    Sometimes it is desirable to let the users of an API provide their own operations, effectively extending the set of operations provided by the API.

    Compelling use case for extensible enumerated type -- Operation codes/ opcodes.

       

    Usage

    1. Pass a single instance of an "extension enum" anywhere a "base enum" is expected.

      /**

      * Demo for "34 Emulate extensible enums with interfaces".

      */

      package com.effectivejava.EnumAnnotations;

         

      /**

      * @author Kaibo

      *

      */

      public interface Operation {

      double apply(double x, double y);

      }

         

      /**

      * Demo for the "34 Emulate extensible enums with interfaces".

      */

      package com.effectivejava.EnumAnnotations;

         

      import java.util.HashMap;

      import java.util.Map;

         

      /**

      * @author Kaibo

      *

      */

      public enum BaseOperation implements Operation {

      PLUS("+") {

      public double apply(double x, double y) {

      return x + y;

      }

      },

      MINUS("-") {

      public double apply(double x, double y) {

      return x - y;

      }

      },

      TIMES("*") {

      public double apply(double x, double y) {

      return x * y;

      }

      },

      DIVIDE("/") {

      public double apply(double x, double y) {

      return x / y;

      }

      };

      private final String symbol;

         

      BaseOperation(String symbol) {

      this.symbol = symbol;

      }

         

      @Override

      public String toString() {

      return symbol;

      }

         

      public abstract double apply(double x, double y);

         

      // Implementing a fromString method on an enum type

      private static final Map<String, BaseOperation> stringToEnum = new HashMap<String, BaseOperation>();

      static { // Initialize map from constant name to enum constant

      for (BaseOperation op : values())

      stringToEnum.put(op.toString(), op);

      }

         

      // Returns BaseOperation for string, or null if string is invalid

      public static BaseOperation fromString(String symbol) {

      return stringToEnum.get(symbol);

      }

      }

         

    2. Pass in an entire extension enum type and use its elements in addition to or instead of those of the base type.

       

    /**

    * Demo for the "34 Emulate extensible enums with interfaces".

    */

    package com.effectivejava.EnumAnnotations;

       

    /**

    * @author Kaibo

    *

    */

    public enum ExtendedOperation implements Operation {

    EXP("^") {

    public double apply(double x, double y) {

    return Math.pow(x, y);

    }

    },

    REMAINDER("%") {

    public double apply(double x, double y) {

    return x % y;

    }

    };

    private final String symbol;

       

    ExtendedOperation(String symbol) {

    this.symbol = symbol;

    }

       

    @Override

    public String toString() {

    return symbol;

    }

    }

       

    Note

    1. Passing the extended enums between methods.
      1. Bounded type token

        public static void main(String[] args) {

        double x = Double.parseDouble(args[0]);

        double y = Double.parseDouble(args[1]);

        test(ExtendedOperation.class, x, y);

        }

        private static <T extends Enum<T> & Operation> void test(

        Class<T> opSet, double x, double y) {

        for (Operation op : opSet.getEnumConstants())

        System.out.printf("%f %s %f = %f%n", x, op, y, op.apply(x, y));

        }

       

    b. Passing with Collection<? Extends Operation>

    public static void main(String[] args) {

    double x = Double.parseDouble(args[0]);

    double y = Double.parseDouble(args[1]);

    test(Arrays.asList(ExtendedOperation.values()), x, y);

    }

       

    private static void test(Collection<? extends Operation> opSet, double x, double y) {

    for (Operation op : opSet)

    System.out.printf("%f %s %f = %f%n", x, op, y, op.apply(x, y));

    }

    2. The logic to store and retrieve the symbol associated with an operation is duplicated in BasicOperation and ExtendedOperation. In this case it doesn't matter because very little code is duplicated. If there were a larger amount of shared functionality, you could encapsulate it in a helper class or a static helper method to eliminate the code duplication.

       

    Summary

    While you cannot write an extensible enum type, you can emulate it by writing an interface to go with a basic enum type that implements the interface.

  • 相关阅读:
    C++ #include .h extern 的相关关系及说明
    VC++ list函数详解
    VC++ 限制窗口的大小范围的方法
    VC++ CTreeCtrl 使用NM_CLICK和TVN_SELCHANGED
    Vc++ 控件用法总结之List Control
    VC++ 将IP字符串转为 DWORD值
    C语言提供了几个标准库函数 itoa() atoi()
    C语言 malloc calloc realloc alloc 在分配内存时的 区别
    C语言 malloc、calloc、realloc的区别
    VC++ MFC中如何将应用程序的配置信息保存到注册表中(二)
  • 原文地址:https://www.cnblogs.com/haokaibo/p/Emulate-extensible-enums-with-interfaces.html
Copyright © 2011-2022 走看看