App 的质量特点
影响 App 质量和用户体会的各种特性。常见的质量特点如下:
- 功用性:App 应具备预期的功用,满足用户的需求。
- 可用性:界面友好,易于运用,用户能够轻松上手。
- 稳定性:很少呈现崩溃、闪退等问题,能够稳定运转。
- 功用:呼应迅速,加载速度快,不呈现卡顿现象。
- 安全性:保护用户的隐私和数据安全。
- 兼容性:适配多种设备和操作系统。
- 可维护性:便于更新和修复问题。
- 可扩展性:能够方便地增加新功用。
- 用户体会:全体体会杰出,让用户感到满足。
- 数据准确性:供给准确的信息。
App重构 (Refactoring)
在不改动
代码外在行为
的前提下,对架构和代码做出修正, 以改进App内部的结构
, 来进步App的质量特点
App重构分为如下两类
1. 架构重构(Re-Architecting)
对现有App从全体结构上进行更改,修正和更新, 相当于做一次大手术, 代价非常贵重
所以需要慎重考虑
, 下面是架构重构的准则
- 清晰重构的意图和
必要性
Hold the line - 界说
重构完结
的边界 Define “Done” -
继续``渐进性
重构 Incrementalism - 熟悉当时的事务和架构状态 Find the start line
- 不要疏忽数据的重要性 Don’t ignore the data
- 办理好技能债务 Manager tech debt better
- 远离虚华的东西(例如运用”热门”的技能栈) Stay away from vanity stuff
- 团队共同,做好预备, Get the team ready
重构过程采用渐进式
重构, 谨慎规划和逐步施行,防止对现有功用发生负面影响。
由底而上
,及时进行测验和验证,保证重构后的 App 仍然满足事务需求和质量标准
首要架构重构方法如下:
- 模块化
- 目录和资源整理,公共资源和东西类的抽离模块化, 然后按照功用进行分包分库
- 把App拆分红多个彼此独立的模块,清晰各模块的
责任
和功用边界
, 到达高内聚、低耦合
方针。
- 组件化
- 在传统的 App 架构中,界面和逻辑往往彼此交织,一旦某个页面需要进行调整或优化,就或许牵一发而动全身。而组件化更侧重于
界面和交互
逻辑的拆分。 - 将界面拆分红独立的组件,每个组件都具有自己的生命周期和状态办理,然后完结了界面逻辑的高度复用宽和耦。
独立开发、测验和部署
。
- 在传统的 App 架构中,界面和逻辑往往彼此交织,一旦某个页面需要进行调整或优化,就或许牵一发而动全身。而组件化更侧重于
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('按钮被点击了');
},
),
),
);
}
}
- 插件化
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('核算'),
),
],
),
),
);
}
}
- 分层架构
分红体现层、事务逻辑层、数据访问层等,进步代码的复用性和可维护性。 - 数据模型优化:
重新规划数据结构和数据库架构,以进步数据访问功用和存储效率。 - 异步处理
运用异步编程技能,如线程、进程或异步使命,进步 App 的呼应性和并发处理能力。 - 接口规划
界说清晰的接口,便于模块之间的通讯和集成。 - 代码抽象:
提取公共功用和逻辑,创立抽象类或接口,进步代码的可复用性。
2.代码重构(Re-Coding)
在不改动代码外部行为的前提下, 有条有理地改善代码,增加可读性或简化结构, 改进App内部质量
Bad Smells(滋味) in Code
代码存在的一些问题,影响代码的质量、可维护性和可读性。以下是常见Bad Smells:
- 重复代码:相同或类似的代码片段在多个当地呈现。
- 过长的函数:函数过于杂乱,包括过多的逻辑。
- 过大的类:类的责任过于广泛,包括过多的功用。
- 神秘代码:缺乏清晰的注释或文档,难以了解代码的意图和功用。
- 过度耦合:不同模块或组件之间严密耦合,修正一个部分或许会影响其他部分。
- 数据泥团:多个类中运用了相同的一组数据。
- 死代码:不再运用或无法到达的代码。
- 条件杂乱:杂乱的条件逻辑,或许难以了解和维护。
- 循环嵌套过深:深层的循环嵌套或许导致功用问题和可读性下降。
常见的代码重构方法
- 函数
- 提取重复代码到独立函数。
- 将大函数分解成几个小函数,单一责任
- 削减嵌套层级(运用if, guard
提早回来
) - 用反常(exception)替代错误码
- 引入断语(assert),检查参数和成果
- 给函数起有意义的姓名。
// 界说一个矩形类
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);
}
}
- 数据
- 削减大局数据的运用
- 合理运用数据结构和封装数据。
- 运用结构函数或设置方法进行目标初始化。
- 常量替代magic number
- 类
- 单一责任: 假如类过于庞大和杂乱,将其分解为更小、更专心的类, 并移除不必要的特点和方法。
- 提取类:假如多个类中有类似的功用,能够将这些功用提取到一个单独的类中,以削减代码重复。
- 运用接口和抽象类:运用接口来界说类的行为,进步代码的灵活性和可扩展性。
- 运用规划形式:合适的规划形式能够改善类的结构和代码的可维护性。
// 界说 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,一起保持代码的简洁和可维护性。