App 的质量特点

影响 App 质量和用户体会的各种特性。常见的质量特点如下:

  1. 功用性:App 应具备预期的功用,满足用户的需求。
  2. 可用性:界面友好,易于运用,用户能够轻松上手。
  3. 稳定性:很少呈现崩溃、闪退等问题,能够稳定运转。
  4. 功用:呼应迅速,加载速度快,不呈现卡顿现象。
  5. 安全性:保护用户的隐私和数据安全。
  6. 兼容性:适配多种设备和操作系统。
  7. 可维护性:便于更新和修复问题。
  8. 可扩展性:能够方便地增加新功用。
  9. 用户体会:全体体会杰出,让用户感到满足。
  10. 数据准确性:供给准确的信息。

App重构 (Refactoring)

不改动代码外在行为的前提下,对架构和代码做出修正, 以改进App内部的结构, 来进步App的质量特点

App重构分为如下两类

1. 架构重构(Re-Architecting)

对现有App从全体结构上进行更改,修正和更新, 相当于做一次大手术, 代价非常贵重

所以需要慎重考虑, 下面是架构重构的准则

  1. 清晰重构的意图和必要性 Hold the line
  2. 界说重构完结的边界 Define “Done”
  3. 继续``渐进性重构 Incrementalism
  4. 熟悉当时的事务和架构状态 Find the start line
  5. 不要疏忽数据的重要性 Don’t ignore the data
  6. 办理好技能债务 Manager tech debt better
  7. 远离虚华的东西(例如运用”热门”的技能栈) Stay away from vanity stuff
  8. 团队共同,做好预备, Get the team ready

重构过程采用渐进式重构, 谨慎规划和逐步施行,防止对现有功用发生负面影响。

由底而上,及时进行测验和验证,保证重构后的 App 仍然满足事务需求和质量标准

首要架构重构方法如下:

  1. 模块化
    1. 目录和资源整理,公共资源和东西类的抽离模块化, 然后按照功用进行分包分库
    2. 把App拆分红多个彼此独立的模块,清晰各模块的责任功用边界, 到达高内聚、低耦合方针。
  2. 组件化
    1. 在传统的 App 架构中,界面和逻辑往往彼此交织,一旦某个页面需要进行调整或优化,就或许牵一发而动全身。而组件化更侧重于界面和交互逻辑的拆分。
    2. 将界面拆分红独立的组件,每个组件都具有自己的生命周期和状态办理,然后完结了界面逻辑的高度复用宽和耦。独立开发、测验和部署
import 'package:flutter/material.dart';
// 界说一个按钮组件ButtonComponent, 该组件接受一个文本字符串和一个点击事情处理函数作为参数,并运用ElevatedButton来创立按钮的外观和行为。
class ButtonComponent extends StatelessWidget {
  const ButtonComponent({Key? key, String text, Function? onPressed}) : super(key: key) {
    final String _text;
    final Function _onPressed;
    // 初始化组件
    ButtonComponent(this._text, this._onPressed);
    // 构建组件的方法
    @override
    Widget build(BuildContext context) {
      return ElevatedButton(
        onPressed: _onPressed,
        child: Text(_text),
      );
    }
  }
}
// 在运用中运用按钮组件
class MyApp extends StatefulWidget {
  @override
  State createState() => MyAppState();
}
class MyAppState extends State<MyApp> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: ButtonComponent(
          text: '点击我',
          onPressed: () {
            // 按钮点击后的逻辑
            print('按钮被点击了');
          },
        ),
      ),
    );
  }
}
  1. 插件化
    App 根据不同用户的需求动态加载对应的插件,然后完结了事务逻辑的灵活装备和办理
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
// 界说一个FlutterCalcPlugin的核算器插件。该插件运用MethodChannel与渠道进行交互,通过native端完结核算逻辑,并将成果回来给调用方。
class FlutterCalcPlugin {
  static const MethodChannel _channel = const MethodChannel('flutter_calc_plugin');
  static Future<int> getPlatformVersion() async {
    final String version = await _channel.invokeMethod('getPlatformVersion');
    return int.parse(version);
  }
  static Future<int> getResult(int a, int b) async {
    final String result = await _channel.invokeMethod('getResult', <String, int>{'a': a, 'b': b});
    return int.parse(result);
  }
}
// 在运用中,导入FlutterCalcPlugin插件,调用FlutterCalcPlugin.getResult方法来执行核算操作,并运用setState来更新核算成果。
class MyApp extends StatefulWidget {
  @override
  State createState() => MyAppState();
}
class MyAppState extends State<MyApp> {
  int _result = 0;
  void _calculate() async {
    final int a = 5;
    final int b = 3;
    final int result = await FlutterCalcPlugin.getResult(a, b);
    setState(() {
      _result = result;
    });
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text('核算成果: $_result'),
            RaisedButton(
              onPressed: _calculate,
              child: Text('核算'),
            ),
          ],
        ),
      ),
    );
  }
}
  1. 分层架构
    分红体现层、事务逻辑层、数据访问层等,进步代码的复用性和可维护性。
  2. 数据模型优化:
    重新规划数据结构和数据库架构,以进步数据访问功用和存储效率。
  3. 异步处理
    运用异步编程技能,如线程、进程或异步使命,进步 App 的呼应性和并发处理能力。
  4. 接口规划
    界说清晰的接口,便于模块之间的通讯和集成。
  5. 代码抽象:
    提取公共功用和逻辑,创立抽象类或接口,进步代码的可复用性。

2.代码重构(Re-Coding)

在不改动代码外部行为的前提下, 有条有理地改善代码,增加可读性或简化结构, 改进App内部质量

Bad Smells(滋味) in Code

代码存在的一些问题,影响代码的质量、可维护性和可读性。以下是常见Bad Smells:

  • 重复代码:相同或类似的代码片段在多个当地呈现。
  • 过长的函数:函数过于杂乱,包括过多的逻辑。
  • 过大的类:类的责任过于广泛,包括过多的功用。
  • 神秘代码:缺乏清晰的注释或文档,难以了解代码的意图和功用。
  • 过度耦合:不同模块或组件之间严密耦合,修正一个部分或许会影响其他部分。
  • 数据泥团:多个类中运用了相同的一组数据。
  • 死代码:不再运用或无法到达的代码。
  • 条件杂乱:杂乱的条件逻辑,或许难以了解和维护。
  • 循环嵌套过深:深层的循环嵌套或许导致功用问题和可读性下降。

常见的代码重构方法

  1. 函数
    1. 提取重复代码到独立函数。
    2. 将大函数分解成几个小函数,单一责任
    3. 削减嵌套层级(运用if, guard提早回来)
    4. 用反常(exception)替代错误码
    5. 引入断语(assert),检查参数和成果
    6. 给函数起有意义的姓名。
// 界说一个矩形类
class Rectangle {
  double length;
  double width;
  Rectangle(double length, double width) {
    this.length = length;
    this.width = width;
  }
}
// 原始的核算面积函数
double originalCalculateArea(Rectangle rectangle) {
  if (rectangle.length <= 0 || rectangle.width <= 0) {
    throw ArgumentError('长度和宽度必须大于 0');
  }
  return rectangle.length * rectangle.width;
}
// 重构后的代码
// 1. 提取重复代码到独立函数:将判别长度和宽度是否大于 0 的逻辑提取到一个单独的函数中
bool isValidRectangle(Rectangle rectangle) {
  return rectangle.length > 0 && rectangle.width > 0;
}
// 2. 将大函数分解成几个小函数,单一责任:将核算面积的逻辑拆分红两个小函数
double calculateArea(Rectangle rectangle) {
  if (!isValidRectangle(rectangle)) {
    throw ArgumentError('无效的矩形参数');
  }
  return rectangle.length * rectangle.width;
}
// 3. 削减嵌套层级 (运用 if, guard 提早回来):运用 guard 句子来提早回来,削减嵌套层级
double calculateLargerSide(Rectangle rectangle) {
  if (rectangle.length > rectangle.width) {
    return rectangle.length;
  } else {
    return rectangle.width;
  }
}
void main() {
  Rectangle rectangle = Rectangle(5.0, 3.0);
  // 4. 用反常 (exception) 替代错误码
  try {
    double area = calculateArea(rectangle);
    print('面积: $area');
    double side = calculateLargerSide(rectangle);
    print('较大边长: $side');
    double square = squareArea(side);
    print('边长为$side 的正方形面积: $square');
  } catch (ArgumentError e) {
    print(e.message);
  }
}
  1. 数据
    1. 削减大局数据的运用
    2. 合理运用数据结构和封装数据。
    3. 运用结构函数或设置方法进行目标初始化。
    4. 常量替代magic number
    1. 单一责任: 假如类过于庞大和杂乱,将其分解为更小、更专心的类, 并移除不必要的特点和方法。
    2. 提取类:假如多个类中有类似的功用,能够将这些功用提取到一个单独的类中,以削减代码重复。
    3. 运用接口和抽象类:运用接口来界说类的行为,进步代码的灵活性和可扩展性。
    4. 运用规划形式:合适的规划形式能够改善类的结构和代码的可维护性。
// 界说 UserRepository 接口
interface UserRepository {
  Future<User> getUserInfo(String userId);
}
//UserInfoManager 类完结 UserRepository 接口
class UserInfoManager implements UserRepository {
  @override
  Future<User> getUserInfo(String userId) {
    // 完结详细的用户信息获取逻辑
    return Future<User>.value(user);
  }
}
// 登录办理器类
class LoginManager {
  final Authenticator authenticator;
  LoginManager(this.authenticator);
  Future<void> login(String username, String password) {
    // 调用 authenticator 进行验证
    if (authenticator.validateCredentials(username, password)) {
      // 登录成功的逻辑
    } else {
      // 登录失利的逻辑
    }
  }
}
// 注册办理器类
class RegistrationManager {
  final UserRepository repository;
  RegistrationManager(this.repository);
  Future<void> register(String username, String password) {
    // 注册用户的逻辑
  }
}
// 在主函数中运用重构后的类
void main() {
  var authenticator = Authenticator();
  var loginManager = LoginManager(authenticator);
  var registrationManager = RegistrationManager(UserInfoManager());
  registrationManager.register('user1', 'pass1');
  loginManager.login('user1', 'pass1');
}

常用规划形式

  • 单例形式(Singleton Pattern):保证类只有一个目标被创立。
  • 工厂形式(Factory Pattern):能够运用工厂形式来封装类创立逻辑。
  • 战略形式(Strategy Pattern):将算法封装为独立的战略类来完结同一使命,在运转时动态挑选。
  • 装饰器形式(Decorator Pattern):不修正原始类的情况下为类增加额定的功用或行为时。
  • 观察者形式(Observer Pattern):当一个目标的状态改动需要通知其他相关目标时, 完结目标之间的解耦。
  • 模板方法形式(Template Method Pattern):根本步骤固定,但子类详细完结能够变化,界说固定的结构,让子类填充详细的步骤。
// 创立三个用于渲染组件的抽象类
abstract class IActivityIndicator {
  Widget render();
}
abstract class ISlider {
  Widget render(double value, ValueSetter<double> onChanged);
}
abstract class ISwitch {
  Widget render(bool value, ValueSetter<bool> onChanged);
}
// 全体页面的抽象类
abstract class IWidgetFactory {
  String getTitle();
  IActivityIndicator createActivityIndicator();
  ISlider createSlider();
  ISwitch createSwitch();
}
// 创立 iOS 风格和 Android 风格的 Widget 实例目标
class MaterialIWidgetsFactory implements IWidgetFactory {
  @override
  IActivityIndicator createActivityIndicator() {
    return AndroidActivityIndicator();
  }
  @override
  ISlider createSlider() {
    return AndroidSlider();
  }
  @override
  ISwitch createSwitch() {
    return AndroidSwitch();
  }
  @override
  String getTitle() {
    return "Android Widgets";
  }
}
class CupertinoWidgetsFactory implements IWidgetFactory {
  @override
  IActivityIndicator createActivityIndicator() {
    return IOSActivityIndicator();
  }
  @override
  ISlider createSlider() {
    return IOSSlider();
  }
  @override
  ISwitch createSwitch() {
    return IOSSwitch();
  }
  @override
  String getTitle() {
    return "iOS Widgets";
  }
}
// 完结 IActivityIndicator 接口
class AndroidActivityIndicator implements IActivityIndicator {
  @override
  Widget render() {
    return CircularProgressIndicator(
      backgroundColor: const Color(0xFFECECEC),
      valueColor: AlwaysStoppedAnimation<Color>(Colors.black.withOpacity(0.65)),
    );
  }
}
// 完结 IOSActivityIndicator 接口
class IOSActivityIndicator implements IActivityIndicator {
  @override
  Widget render() {
    return CupertinoActivityIndicator();
  }
}

界说抽象类,然后完结这些抽象类来创立详细的Widget实例目标。优势在于能够方便地扩展和替换不同风格的Widget,一起保持代码的简洁和可维护性。