extension —— 无侵入扩展 Dart 类

前言

在做 iOS 开发的时候,Objective-C 语言有个特性,叫 Category,也就是可以在不修改原有类代码的基础上扩展一个类的方法或静态属性。Dart 语言同样借鉴了这种设计,只是换了个更贴切的说法,叫做 extension。通过 extension 可以以无侵入的方式扩展一个已有的类,从而不影响其他使用这个类的代码。本篇来介绍 extension 的使用以及典型的应用。

extension 介绍

要使用Dart 的 extension 扩展类很简单,只需要新增一个 Dart 文件,然后按下面的方式声明即可:

dart 复制代码
extension [扩展名称] on [已有类名] {
  static const [静态属性] = ...;

  [已有类名] get [get属性] = ...;

  [方法名](参数) {
    //方法体
  }
}

这里需要注意,extension不支持扩展非静态属性。

应用之扩展颜色

我们在 App 中经常会依据设计规范设置主题色、辅助色、标题字体颜色、分割线颜色等等。虽然可以通过 Theme 来实现,但是 Theme依赖于 Context。我们也可以定义一个主体颜色扩展,来定义我们所需要的颜色,当设计稿更改颜色时,只需要更改这个颜色扩展就可以完成所有颜色的修改。下面是示例代码:

dart 复制代码
extension ThemeColor on Color {
  static const primaryColor = Color(0xFF0990EC);
  static const lineColor = Color(0xFFEEEEEE);

  //反色
  Color get reverseColor {
    return Color.fromARGB(
      alpha,
      255 - red,
      255 - green,
      255 - blue,
    );
  }
	// 将颜色转换为16进制字符串表示,例如:#FFFF0000
  String toHex() {
    return '#${value.toRadixString(16).padLeft(6, 'F').toUpperCase()}';
  }
}

应用之屏幕适配

设计师提供的设计稿通常会按照某一个屏幕的宽度尺寸设计,例如375是设计师常用的一个设计宽度。但是实际屏幕的宽度却五花八门,这个时候就需要做屏幕适配。在 Flutter 屏幕适配插件中,screen_util 是应用最为广泛(中文文档:github.com/OpenFlutter...)。如果我们去看里面的源码,就会发现里面就用到了extension,其中典型的就是扩展了 num 类。

dart 复制代码
extension SizeExtension on num {
  ///[ScreenUtil.setWidth]
  double get w => ScreenUtil().setWidth(this);

  ///[ScreenUtil.setHeight]
  double get h => ScreenUtil().setHeight(this);

  ///[ScreenUtil.radius]
  double get r => ScreenUtil().radius(this);

  ///[ScreenUtil.diagonal]
  double get dg => ScreenUtil().diagonal(this);

  ///[ScreenUtil.diameter]
  double get dm => ScreenUtil().diameter(this);

  ///[ScreenUtil.setSp]
  double get sp => ScreenUtil().setSp(this);

  //...
}

原理上其实就是用实际屏幕尺寸与设计稿尺寸计算比例,然后再将这个比例乘以定义组件尺寸的数值。比如20.w,实际上就是20乘以换算的比例得到适配后的宽度。典型的例子就是一个固定宽度的 Container,屏幕越大应该宽度越宽,这样两侧的留白也不至于过宽。 这里我们还可以发现,如果是在父类上进行扩展,那么这些扩展对子类也是可以生效的。比如上面扩展的是 num 类,那么对于 doubleint 这样的子类也是可以用 num 类的扩展方法的。

应用之简化校验

第三类应用就是表单校验,实际上大部分都是字符串校验,那么我们可以编写一个字符串校验扩展类,将我们用到的字符串校验集中在一起,如下所示。

dart 复制代码
extension StringValidator on String {
  bool get isEmail {
    //邮箱校验逻辑
  }

  bool get isIdNumber {
    //身份证号校验
  }

  bool get isMobile {
    //手机号校验
  }

  //...
}

这样用起来会更方便,如下所示:

dart 复制代码
if (!email.isEmail) {
  //邮箱校验失败处理
}

if (!mobile.isMobile) {
  //手机号校验失败处理
}

相比单独定义一个校验类,编写静态方法来说,这样的方式的代码显然更加简洁。

总结

代码开发的一个重要原则是"对扩展开放,对修改封闭"。这是因为扩展的代码不会影响已有的业务代码,而修改则会影响所有用到修改部分的代码。使用 extension 就很好地遵循了这一原则,不更改原有的类代码,因此不影响类的原有使用方式。同时,又扩展了类的特性,使得扩展后的代码可以适用特定的场景。如果你在开发 Flutter 的应用中,发现经常要对某个类进行相同的处理,那么或许使用 extension 扩展会是一个更好的选择。

我是岛上码农,微信公众号同名。如有问题可以加本人微信交流,微信号:island-coder

👍🏻:觉得有收获请点个赞鼓励一下!

🌟:收藏文章,方便回看哦!

💬:评论交流,互相进步!

相关推荐
用户9272472502193 分钟前
新闻自动采集并通过API发布到博客
前端·后端
清风92006 分钟前
Logback——日志技术(基础)
java·前端·logback
EndingCoder6 分钟前
排序算法与前端交互优化
开发语言·前端·javascript·算法·排序算法·交互
咕噜签名分发冰淇淋21 分钟前
申请注册苹果iOS企业级开发者证书需要公司拥有什么规模条件
macos·ios·cocoa
三月的一天31 分钟前
在 React Three Fiber 中实现 3D 模型点击扩散波效果
前端·react.js·前端框架
爱敲代码的小冰31 分钟前
npm 切换 node 版本 和npm的源
前端·npm·node.js
DoraBigHead37 分钟前
🧠【彻底读懂 reduce】acc 是谁?我是谁?我们要干嘛?
前端·javascript·面试
future14121 小时前
项目开发日记
前端·学习·c#·游戏开发
汪子熙1 小时前
CSS 中 td:last-child a 选择器详解
前端·javascript
北北~Simple1 小时前
第一次搭建数据库
服务器·前端·javascript·数据库