阅读 177

fish_redux slots Connector 泛型适配器

制作背景:在使用闲鱼的fish_redux框架的时候就会遇到每次编辑一个slots都需要创建一个connector连接器,这件事使得我非常的不开心。我就想能不能编写一个能够适配不同component的适配器,接下来就开始思考这个问题。 要实现不同component使用同一个connector连接器,使用泛型就非常的适合。 首先我们看到fish_redux的例子里面: 其中page里面有slots槽连接

slots: <String, Dependent<PageState>>{
  'report': ReportConnector() + ReportComponent()
}),复制代码

他这里每次使用一个component都要创建一个connector连接器,我们就需要根据不同的state对象将T(泛型)的适配,我们再来看一看ReportConnector这个类,这里面有两个state,分别是当前pagestatePageState)和componentstateReportState),就需要用到两个 TP(泛型),将对应的state使用TP(泛型)替换掉。(以下我们用T(泛型)代表PageStateP(泛型)代表ReportState),ReportConnector也需要制定两个 TP(泛型)传入进来。

class ReportConnector extends ConnOp<PageState, ReportState>
    with ReselectMixin<PageState, ReportState> {
  @override
  ReportState computed(PageState state) {
    return ReportState()
      ..done = state.toDos.where((ToDoState tds) => tds.isDone).length
      ..total = state.toDos.length;
  }

  @override
  List<dynamic> factors(PageState state) {
    return <int>[
      state.toDos.where((ToDoState tds) => tds.isDone).length,
      state.toDos.length
    ];
  }

  @override
  void set(PageState state, ReportState subState) {
    throw Exception('Unexcepted to set PageState from ReportState');
  }
}
改
class ReportConnector<T, P> extends ConnOp<T, P>
    with ReselectMixin<T, P> {
  @override
  P computed(T state) {
    return ReportState()
      ..done = state.toDos.where((ToDoState tds) => tds.isDone).length
      ..total = state.toDos.length;
  }

  @override
  List<dynamic> factors(PageState state) {
    return <int>[
      state.toDos.where((ToDoState tds) => tds.isDone).length,
      state.toDos.length
    ];
  }

  @override
  void set(T state, P subState) {
    throw Exception('Unexcepted to set PageState from ReportState');
  }
}复制代码

这里我们再看看这里面的一些方法,其中computed方法返回的是P(泛型),但是传入的是T(泛型),我们怎么从T(泛型)中拿到这个P(泛型)呢,这个问题值得思考以下。

首先要解耦的话我们只能通过T(泛型)去获取这个P(泛型),那这个T(泛型)就需要有个P(泛型),那我们需要在这个T(泛型)添加一个P(泛型),添加完了怎么去获取出来呢,这里思考以下。因为T(泛型)默认继承的是dynamic类型,不能直接把P(泛型)取出来,所以就需要继承一个基类,我在这是新建了一个abstract类为BaseConnector,并且这里P(泛型)ReportState.

abstract class BaseConnector<T>{
    ReportState get state => ReportState();
}复制代码

这样ReportConnector传入T(泛型)就可以继承BaseConnector从而取出P(泛型)

class ReportConnector<T, P> extends ConnOp<T, P>
    with ReselectMixin<T, P>
改
class ReportConnector<T extends BaseConnector, P> extends ConnOp<T, P>
    with ReselectMixin<T, P> 
复制代码

现在我们在computed方法中通过T(泛型)取出P(泛型),这样我们就获取到了P(泛型)

P computed(T state) {
    return state.state;
}复制代码

但是如果BaseConnector这里面编写固定为ReportState的话也不是很理想,这样就固定话ReportState这个state了,我们可以用一个T(泛型)来代替。再由于slots槽可以放置多个component,就不能单一的只获取其中的一种state,就需要用List数组来承载多个state,将其命名为args

abstract class BaseConnector<T>{
    ReportState get state => ReportState();
}
改
abstract class BaseConnector<T>{
    T state;
}
再改
abstract class BaseConnector{
    List get getArgs => [];
}复制代码

然后回到computed方法上面,我们需要把多个state都承载出来,对应返回给P(泛型)

P computed(T state) {
    return state.state;
}
改
P computed(T state) {
  List args = args ?? state.getArgs;
  if(args!=null){
    // 遍历args数组,并且一一进行类型比较,当类型为P(泛型)类型后就返回对应的state
    for(Object object in args){
      if(object.runtimeType == P){
        args = null;
        return object;
      }
    }
  }
  args = null;
  return null;
}复制代码

那么返回对应的state算是完成了,那我们在呢么去更新这个对应的state呢,来看到set方法,目前他这个set方法throw出了一个异常,说的是需要修改PageState里面的ReportState,一开始我们是修改一个使用state.state = subState;,但是我们需要修改多个,就需要便利args数组,一一替换对应的state

void set(T state, P subState) {
    throw Exception('Unexcepted to set PageState from ReportState');
}
改
void set(T state, P subState) {
    state.state = subState;
}
再改
void set(T state, P subState) {
  List args = state.getArgs;
  if(args!=null){
    // 遍历args数组,并且一一进行类型比较,当类型为P(泛型)类型后就替换对应的state
    for(int i = 0;i < args.length;i++){
      if(args[i].runtimeType == P){
        args[i] = subState;
      }
    }
  }
}复制代码

因为每次修改后list都会改变,就需要定义一个list成员变量来保存每次修改后的数组

List args;

P computed(T state) {
  args = args ?? state.getArgs;
  if(args!=null){
    // 遍历args数组,并且一一进行类型比较,当类型为P(泛型)类型后就返回对应的state
    for(Object object in args){
      if(object.runtimeType == P){
        args = null;
        return object;
      }
    }
  }
  args = null;
  return null;
}

void set(T state, P subState) {
  args = state.getArgs;
  if(args!=null){
    // 遍历args数组,并且一一进行类型比较,当类型为P(泛型)类型后就替换对应的state
    for(int i = 0;i < args.length;i++){
      if(args[i].runtimeType == P){
        args[i] = subState;
      }
    }
  }
}复制代码

这样的话链接器就算是完成了,修改了几处泛型就解决了每次需要创建connector连接器的问题 下面是使用方式,无需重复创建connector连接器,直接在slots里面添加component即可使用,只需要加上对应的state即可。

slots: <String, Dependent<PageState>>{
  'report': ReportConnector() + ReportComponent()
}),
slots: <String, Dependent<PageState>>{
  "report": Connector<PageState,ReportState>() + ReportComponent(),
}),复制代码

编写完毕,下面贴上我的代码

connector.dart

abstract class BaseConnector{
    List get getArgs => [];
}

class Connector<T extends BaseConnector, P> extends ConnOp<T, P>
    with ReselectMixin<T, P> {

  List args;

  @override
  P computed(T state) {
    args = args ?? state.getArgs;
    if(args!=null){
      for(Object object in args){
        if(object.runtimeType == P){
          args = null;
          return object;
        }
      }
    }
    args = null;
    return null;
  }

  @override
  void set(T state, P subState) {
    args = state.getArgs;
    if(args!=null){
      for(int i = 0;i < args.length;i++){
        if(args[i].runtimeType == P){
          args[i] = subState;
        }
      }
    }
  }
}复制代码

page.dart

class CityPage extends Page<CityState, Map<String, dynamic>> {
  CityPage()
      : super(
            initState: initState,
            effect: buildEffect(),
            reducer: buildReducer(),
            view: buildView,

            dependencies: Dependencies<CityState>(
                adapter: null,
                slots: <String, Dependent<CityState>>{
                  "header_component": Connector<CityState,HeaderState>() + HeaderComponent(),
                  "tools_component": Connector<CityState,ToolsState>() + ToolsComponent(),
                  "body_component": Connector<CityState,BodyState>() + BodyComponent(),
                }),
            middleware: <Middleware<CityState>>[
            ],);

}复制代码

state.dart 这里也需要实现一下BaseConnector

class CityState implements Cloneable<CityState> , BaseConnector {

  List<ToolModel> list = <ToolModel>[];

  int style = 0;

  @override
  CityState clone() {
    return CityState()..list=list..style=style..getArgs;
  }

  @override
  List get getArgs => [
    HeaderState(),
    ToolsState()..list=list,
    BodyState(),
  ];
}

CityState initState(Map<String, dynamic> args) {
  return CityState();
}复制代码

总结:将state泛型化能够更好的降低者之间的耦合度,减少代码的冗余,增加复用性,变得不那么僵硬、那么固定化,能够更好的发挥连接器的配置性。


作者:RogueYBJ
链接:https://juejin.cn/post/7020654999763959821


文章分类
后端
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐