美文网首页
Kotlin Sealed Class 太香了,Java 8 也

Kotlin Sealed Class 太香了,Java 8 也

作者: super可乐 | 来源:发表于2022-09-02 13:42 被阅读0次

    为避免数据在分发过程中被恶意篡改,Kotlin 将 SealedClass 参数设置为 val 即可,

    Java 17 以下未引入 SealedClass,且若实现 Kotlin val 同等效果,样板代码瞬间飙出许多,等于解决了数据一致性的同时,滋生了更多 “不一致” 问题,例如日后修改某字段,而忘配置构造方法等等。

    痛定思痛,SealedClass4Java 应运而生,通过注解自动生成 SealedClass,像 Kotlin 一样使用 SealedClass。

    献给喜欢 Kotlin 但又不得不维护 Java 老项目的朋友。

    Github:SealedClass4Java

    使用说明

    1.创建一个接口,添加 SealedClass 注解,且接口名开头 _ 下划线,

    @SealedClass
    public interface _TestEvent {
      void resultTest1(String a, int b);
      void resultTest2(String a, int b, int c);
    }
    

    2.编译即可生成目标类,例如 TestEvent,然后像 Kotlin 一样使用该类:

    TestEvent event = TestEvent.ResultTest1("textx");
    
    switch (event.id) {
      case TestEvent.ResultTest1.ID:
        TestEvent.ResultTest1 event1 = (TestEvent.ResultTest1) event;
        event1.copy(1);
        event1.paramA;
        event1.resultB;
        break;
      case TestEvent.ResultTest2.ID:
        break;
    }
    
    

    进阶使用

    本框架是 MVI-Dispatcher 项目优化过程中,为消除 “消息分流场景 final 样板代码” 而萌生的产物,所以我们不妨以 MVI-Dispatcher 使用场景为例:

    注:“消息(message)、事件(event)、意图(intent)”,不同场景,叫法不同,但本质上是指同一东西,即 “可被消费的一次性数据”。

    A.纯粹消息分发场景

    1.定义一个接口,例如 _Messages,在方法列表中定义不携带参数的纯粹消息,定义完 build 生成对应 Messages 类。

    @SealedClass
    public interface _Messages {
      void refreshNoteList();
      void finishActivity();
    }
    

    2.在 MVI-View 中发送一个 Messages.RefreshNoteList( ) 纯粹消息

    public class TestFragment {
      public void onInput() {
        MVI-Model.input(Messages.RefreshNoteList());
      }
    }
    

    3.在 MVI-Model 中转发消息

    public class PageMessenger extends MVI-Disptacher {
      protected void onHandle(Messages intent){
        sendResult(intent);
      }
    }
    

    4.在 MVI-View 中响应消息

    public class TestFragment {
      public void onOutput() {
        MVI-Model.output(this, intent-> {
          switch(intent.id) {
            case Messages.RefreshNoteList.ID: ... break;
            case Messages.FinishActivity.ID: ... break;
          }
        });
      }
    }
    

    B.带参数的意图分发场景

    该场景十分普遍,例如页面向后台请求一数据,通过意图来传递参数,后台处理好结果,将结果注入到意图中,回传给页面。

    所以该场景下,意图会携带 “参数” 和 “结果”,且发送场景下只需注入参数,回推场景下只需注入结果,

    因而使用方法即,

    1.定义接口,为参数添加 @Param 注解,

    @SealedClass
    public interface _NoteIntent {
      void addNote(@Param Note note, boolean isSuccess);
      void removeNote(@Param Note note, boolean isSuccess);
    }
    

    build 生成的静态方法,比如 AddNote 方法中,只提供 “参数” 列表,不提供结果列表,结果字段皆赋予默认值,以符合意图发送场景的使用。

    public static NoteIntent AddNote(Note note) {
      return new AddNote(note, false);
    }
    

    2.在 MVI-View 中发送一个 NoteIntent.AddNote(note) 意图,

    public class TestFragment {
      public void onInput() {
        MVI-Model.input(NoteIntent.AddNote(note));
      }
    }
    

    3.在 MVI-Model 中处理业务逻辑,注入结果和回推意图。

    由于意图为确保 “数据一致性” 而不可修改,因此在注入结果的场景下,可通过 copy 方法拷贝一份新的意图,而 copy 方法的入参即 “结果” 列表,以符合意图回推场景的使用。

    public class NoteRequester extends MVI-Disptacher {
      protected void onHandle(NoteIntent intent){
        switch(intent.id) {
          case NoteIntent.AddNote.ID: 
            DataRepository.instance().addNote(result -> {
              NoteIntent.AddNote addNote = (NoteIntent.AddNote) intent;
              sendResult(addNote.copy(result.isSuccess));
            });
            break;
          case NoteIntent.RemoveNote.ID: 
            ...
            break;
        }
      }
    }
    

    4.在 MVI-View 中响应意图

    public class TestFragment {
      public void onOutput() {
        MVI-Model.output(this, intent-> {
          switch(intent.id) {
            case NoteIntent.AddNote.ID: 
              updateUI();
              break;
            case NoteIntent.RemoveNote.ID: 
              ...
              break;
          }
        });
      }
    }
    

    C.不带参的事件分发场景

    也即没有初值传参,只用于结果分发的情况。

    这种场景和 “带参数意图分发场景” 通常重叠和互补,所以使用上其实大同小异。

    1.定义接口,方法不带 @Param 注解。那么该场景下 NoteIntent.GetNotes 静态方法提供无参和有参两种,我们通常是使用无参,也即事件在创建时结果是被给到默认值。

    @SealedClass
    public interface _NoteIntent {
      void getNotes(List<Note> notes);
    }
    

    2.在 MVI-View 中发送一个 NoteIntent.GetNotes() 事件,

    public class TestFragment {
      public void onInput() {
        MVI-Model.input(NoteIntent.GetNotes());
      }
    }
    

    3.在 MVI-Model 中处理业务逻辑,注入结果和回推意图。

    由于意图为确保 “数据一致性” 而不可修改,因此在注入结果的场景下,可通过 copy 方法拷贝一份新的意图,而 copy 方法的入参即 “结果” 列表,以符合意图回推场景的使用。

    public class NoteRequester extends MVI-Disptacher {
      protected void onHandle(NoteIntent intent){
        switch(intent.id) {
          case NoteIntent.GetNotes.ID: 
            DataRepository.instance().getNotes(result -> {
              NoteIntent.GetNotes getNotes = (NoteIntent.GetNotes) intent;
              sendResult(getNotes.copy(result.notes));
            });
            break;
          case NoteIntent.RemoveNote.ID: 
            ...
            break;
        }
      }
    }
    

    4.在 MVI-View 中响应事件

    public class TestFragment {
      public void onOutput() {
        MVI-Model.output(this, intent-> {
          switch(intent.id) {
            case NoteIntent.GetNotes.ID: 
              updateUI();
              break;
            case NoteIntent.RemoveNote.ID: 
              ...
              break;
          }
        });
      }
    }
    

    Github:SealedClass4Java

    作者:KunMinX
    链接:https://juejin.cn/post/7137571636781252622

    相关文章

      网友评论

          本文标题:Kotlin Sealed Class 太香了,Java 8 也

          本文链接:https://www.haomeiwen.com/subject/exaenrtx.html