• Java-Enum常量特定方法


    OnJava8-Enum-常量特定方法

    用枚举实现责任链模式

    责任链(Chain Of Responsibility)设计模式先创建了一批用于解决目标问题的不同方法,然后将它们连成一条“链”。

    当一个请求先到达时,会顺着这条链传递下去,直到遇到链上某个可以处理该请求的方法。

    可以很容易地用常量特定方法实现一条简单的责任链。考虑一个邮局模型,它对每一封邮件都会尝试用最常见的方式来处理,(如果行不通)并不断尝试别的方式,直到该邮件最终被视为“死信”(无法投递)。每种尝试可以看作一个策略(另一种设计模式),而整个策略列表放在一起就是一条责任链。

    我们从一封邮件开始说起。它所有的重要特征都可以用来枚举表达。由于Mail对象是随机创建的,想要减小一封邮件的GenralDelivery被赋予YES的可能性,最简单的方法是创建更多的非YES的实例,因此枚举的定义一开始可能看起来有点好笑。

    在Mail中,你会看到randomMail()方法,用来随机创建测试邮件。generator方法生成了一个Iterable对象,它使用randomMail方法来生成一定数量的Mail对象,每通过迭代器调用一次next()就会生成一个。这种结构允许通过调用Mail.genrator()方法实现for-in循环的简单创建能力。

    首先对邮件进行建模:

    package org.example.onjava.senior.example01enum.desgin;
    
    import org.example.onjava.onjavaUtils.Enums;
    
    import java.util.Iterator;
    
    /**
     * @Author Coder_Pans
     * @Date 2022/11/20 09:32
     * @PackageName:org.example.onjava.senior.example01enum.desgin
     * @ClassName: Mail
     * @Description: TODO 邮件建模
     * @Version 1.0
     */
    public class Mail {
        enum GeneralDelivery {YES,NO1,NO2,NO3,NO4,NO5}
        enum Scannability {UNSCANNABLE,YES1,YES2,YES3,YES4}
        enum Readability {ILLEGIBLE,YES1,YES2,YES3,YES4}
        enum Address {INCORRECT,OK1,OK2,OK3,OK4,OK5,OK6}
        enum ReturnAddress {MISSING,OK1,OK2,OK3,OK4,OK5}
        GeneralDelivery generalDelivery;
        Scannability scannability;
        Readability readability;
        Address address;
        ReturnAddress returnAddress;
        static long counter = 0;
        long id = counter++;
        @Override public String toString() {
            return "Mail " + id;
        }
        public String details() {
            return toString() +
                    ", General Delivery: " + generalDelivery +
                    ", Address Scannability: " + scannability +
                    ", Address Readability: " + readability +
                    ", Address Address: " + address +
                    ", Return address: " + returnAddress;
        }
        // Generate test Mail:
        public static Mail randomMail() {
            Mail m = new Mail();
            m.generalDelivery =
                    Enums.random(GeneralDelivery.class);
            m.scannability =
                    Enums.random(Scannability.class);
            m.readability =
                    Enums.random(Readability.class);
            m.address = Enums.random(Address.class);
            m.returnAddress =
                    Enums.random(ReturnAddress.class);
            return m;
        }
        public static
        Iterable<Mail> generator(final int count) {
            return new Iterable<Mail>() {
                int n = count;
                @Override public Iterator<Mail> iterator() {
                    return new Iterator<Mail>() {
                        @Override public boolean hasNext() {
                            return n-- > 0;
                        }
                        @Override public Mail next() {
                            return randomMail();
                        }
                        @Override
                        public void remove() { // Not implemented
                            throw new UnsupportedOperationException();
                        }
                    };
                }
            };
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73

    创建常量特定方法:

    package org.example.onjava.senior.example01enum.desgin;
    
    public class PostOffice {
      enum MailHandler {
        GENERAL_DELIVERY {
          @Override boolean handle(Mail m) {
            switch(m.generalDelivery) {
              case YES:
                System.out.println(
                  "Using general delivery for " + m);
                return true;
              default: return false;
            }
          }
        },
        MACHINE_SCAN {
          @Override boolean handle(Mail m) {
            switch(m.scannability) {
              case UNSCANNABLE: return false;
              default:
                switch(m.address) {
                  case INCORRECT: return false;
                  default:
                    System.out.println(
                      "Delivering "+ m + " automatically");
                    return true;
                }
            }
          }
        },
        VISUAL_INSPECTION {
          @Override boolean handle(Mail m) {
            switch(m.readability) {
              case ILLEGIBLE: return false;
              default:
                switch(m.address) {
                  case INCORRECT: return false;
                  default:
                    System.out.println(
                      "Delivering " + m + " normally");
                    return true;
                }
            }
          }
        },
        RETURN_TO_SENDER {
          @Override boolean handle(Mail m) {
            switch(m.returnAddress) {
              case MISSING: return false;
              default:
                System.out.println(
                  "Returning " + m + " to sender");
                return true;
            }
          }
        };
        abstract boolean handle(Mail m);
      }
      static void handle(Mail m) {
        for(MailHandler handler : MailHandler.values())
          if(handler.handle(m))
            return;
        System.out.println(m + " is a dead letter");
      }
      public static void main(String[] args) {
        for(Mail mail : Mail.generator(10)) {
          System.out.println(mail.details());
          handle(mail);
          System.out.println("*****");
        }
      }
    }
    /* Output:
    Mail 0, General Delivery: NO2, Address Scannability:
    UNSCANNABLE, Address Readability: YES3, Address
    Address: OK1, Return address: OK1
    Delivering Mail 0 normally
    *****
    Mail 1, General Delivery: NO5, Address Scannability:
    YES3, Address Readability: ILLEGIBLE, Address Address:
    OK5, Return address: OK1
    Delivering Mail 1 automatically
    *****
    Mail 2, General Delivery: YES, Address Scannability:
    YES3, Address Readability: YES1, Address Address: OK1,
    Return address: OK5
    Using general delivery for Mail 2
    *****
    Mail 3, General Delivery: NO4, Address Scannability:
    YES3, Address Readability: YES1, Address Address:
    INCORRECT, Return address: OK4
    Returning Mail 3 to sender
    *****
    Mail 4, General Delivery: NO4, Address Scannability:
    UNSCANNABLE, Address Readability: YES1, Address
    Address: INCORRECT, Return address: OK2
    Returning Mail 4 to sender
    *****
    Mail 5, General Delivery: NO3, Address Scannability:
    YES1, Address Readability: ILLEGIBLE, Address Address:
    OK4, Return address: OK2
    Delivering Mail 5 automatically
    *****
    Mail 6, General Delivery: YES, Address Scannability:
    YES4, Address Readability: ILLEGIBLE, Address Address:
    OK4, Return address: OK4
    Using general delivery for Mail 6
    *****
    Mail 7, General Delivery: YES, Address Scannability:
    YES3, Address Readability: YES4, Address Address: OK2,
    Return address: MISSING
    Using general delivery for Mail 7
    *****
    Mail 8, General Delivery: NO3, Address Scannability:
    YES1, Address Readability: YES3, Address Address:
    INCORRECT, Return address: MISSING
    Mail 8 is a dead letter
    *****
    Mail 9, General Delivery: NO1, Address Scannability:
    UNSCANNABLE, Address Readability: YES2, Address
    Address: OK1, Return address: OK4
    Delivering Mail 9 normally
    *****
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124

    责任链模式的作用体现在了MailHandler枚举中,枚举的定义顺序则决定了各个策略在每封邮件上被应用的顺序。该模式会按顺序尝试应用每个策略,直到某个策略执行成功,或者全部策略都执行失败(即邮件无法投递)

    用枚举实现状态机

    枚举类型很适合用来实现状态机。状态机可以处于有限数量的特定状态。它们通常根据输入,从一个状态转移到下一个状态,但同时也会存在瞬态。当任务执行完毕后,状态机会立即跳出所有状态。

    每个状态一般也会有某种对应的输出。

    通过自动售货机案例来了解如何实现状态机,首先,在一个枚举中定义一系列输入:

    /**
     * 用枚举实现状态机  01
     */
    public enum Input {
      NICKEL(5), DIME(10), QUARTER(25), DOLLAR(100),
      TOOTHPASTE(200), CHIPS(75), SODA(100), SOAP(50),
      ABORT_TRANSACTION {
        @Override public int amount() { // Disallow
          throw new RuntimeException("ABORT.amount()");
        }
      },
      STOP { // This must be the last instance.
        @Override public int amount() { // Disallow
          throw new
            RuntimeException("SHUT_DOWN.amount()");
        }
      };
      int value; // In cents
      Input(int value) { this.value = value; }
      Input() {}
      int amount() { return value; }; // In cents
      static Random rand = new Random(47);
      public static Input randomSelection() {
        // Don't include STOP:
        return
          values()[rand.nextInt(values().length - 1)];
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    VendingMachine(自动售货机)接收到输入后,首先通过Category(类别)枚举来对这些输入进行分类,这样就可以在各个类别间切换了。

    package org.example.onjava.senior.example01enum.desgin;// enums/VendingMachine.java
    // (c)2021 MindView LLC: see Copyright.txt
    // We make no guarantees that this code is fit for any purpose.
    // Visit http://OnJava8.com for more book information.
    // {java VendingMachine VendingMachineInput.txt}
    
    import java.io.IOException;
    import java.nio.file.Files;
    import java.nio.file.Paths;
    import java.util.Arrays;
    import java.util.EnumMap;
    import java.util.Iterator;
    import java.util.function.Supplier;
    import java.util.stream.Collectors;
    
    enum Category {
      MONEY(Input.NICKEL, Input.DIME,
            Input.QUARTER, Input.DOLLAR),
      ITEM_SELECTION(Input.TOOTHPASTE, Input.CHIPS,
                     Input.SODA, Input.SOAP),
      QUIT_TRANSACTION(Input.ABORT_TRANSACTION),
      SHUT_DOWN(Input.STOP);
      private Input[] values;
      Category(Input... types) { values = types; }
      private static EnumMap<Input,Category> categories =
        new EnumMap<>(Input.class);
      static {
        for(Category c : Category.class.getEnumConstants())
          for(Input type : c.values)
            categories.put(type, c);
      }
      public static Category categorize(Input input) {
        return categories.get(input);
      }
    }
    
    public class VendingMachine {
      private static State state = State.RESTING;
      private static int amount = 0;
      private static Input selection = null;
      enum StateDuration { TRANSIENT } // Tagging enum
      enum State {
        RESTING {
          @Override void next(Input input) {
            switch(Category.categorize(input)) {
              case MONEY:
                amount += input.amount();
                state = ADDING_MONEY;
                break;
              case SHUT_DOWN:
                state = TERMINAL;
              default:
            }
          }
        },
        ADDING_MONEY {
          @Override void next(Input input) {
            switch(Category.categorize(input)) {
              case MONEY:
                amount += input.amount();
                break;
              case ITEM_SELECTION:
                selection = input;
                if(amount < selection.amount())
                  System.out.println(
                    "Insufficient money for " + selection);
                else state = DISPENSING;
                break;
              case QUIT_TRANSACTION:
                state = GIVING_CHANGE;
                break;
              case SHUT_DOWN:
                state = TERMINAL;
              default:
            }
          }
        },
        DISPENSING(StateDuration.TRANSIENT) {
          @Override void next() {
            System.out.println("here is your " + selection);
            amount -= selection.amount();
            state = GIVING_CHANGE;
          }
        },
        GIVING_CHANGE(StateDuration.TRANSIENT) {
          @Override void next() {
            if(amount > 0) {
              System.out.println("Your change: " + amount);
              amount = 0;
            }
            state = RESTING;
          }
        },
        TERMINAL {@Override
        void output() { System.out.println("Halted"); } };
        private boolean isTransient = false;
        State() {}
        State(StateDuration trans) { isTransient = true; }
        void next(Input input) {
          throw new RuntimeException("Only call " +
            "next(Input input) for non-transient states");
        }
        void next() {
          throw new RuntimeException(
            "Only call next() for " +
            "StateDuration.TRANSIENT states");
        }
        void output() { System.out.println(amount); }
      }
      static void run(Supplier<Input> gen) {
        while(state != State.TERMINAL) {
          state.next(gen.get());
          while(state.isTransient)
            state.next();
          state.output();
        }
      }
      public static void main(String[] args) {
        Supplier<Input> gen = new RandomInputSupplier();
        if(args.length == 1)
          gen = new FileInputSupplier(args[0]);
        run(gen);
      }
    }
    
    // For a basic sanity check:
    class RandomInputSupplier implements Supplier<Input> {
      @Override public Input get() {
        return Input.randomSelection();
      }
    }
    
    // Create Inputs from a file of ';'-separated strings:
    class FileInputSupplier implements Supplier<Input> {
      private Iterator<String> input;
      FileInputSupplier(String fileName) {
        try {
          input = Files.lines(Paths.get(fileName))
            .skip(1) // Skip the comment line
            .flatMap(s -> Arrays.stream(s.split(";")))
            .map(String::trim)
            .collect(Collectors.toList())
            .iterator();
        } catch(IOException e) {
          throw new RuntimeException(e);
        }
      }
      @Override public Input get() {
        if(!input.hasNext())
          return null;
        return Enum.valueOf(
          Input.class, input.next().trim());
      }
    }
    /* Output:
    25
    50
    75
    here is your CHIPS
    0
    100
    200
    here is your TOOTHPASTE
    0
    25
    35
    Your change: 35
    0
    25
    35
    Insufficient money for SODA
    35
    60
    70
    75
    Insufficient money for SODA
    75
    Your change: 75
    0
    Halted
    */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
  • 相关阅读:
    关于火绒邮件监控引起的扫描任意IP会有25和110端口反馈
    java发送媒体类型为multipart/form-data的请求
    IMU标定之---Allan方差
    在没有康托尔对角化方法的情况下证明实数的不可数性
    (10)学习笔记:动手深度学习(模型选择 + 过拟合和欠拟合)
    springboot新冠疫苗预约管理系统毕业设计-附源码241530
    Set集合(超详解)
    Python学习笔记--通过慢慢演变一个需求,一步一步来了解 Python 装饰器
    jsp基础语法
    【编程题】【Scratch三级】2021.06 计算成绩总和
  • 原文地址:https://blog.csdn.net/weixin_45688141/article/details/127949057