3

问题描述

用户需求变动,最近一直在修改之前的项目,虽然一直在执行重复的工作,但是也有了些重构项目的心得。

体会

最小改动

在原有的项目上修改,应该是“最小程度”地修改现有的设计。

使外部不知道本模块有所改动,也就是常说的高内聚低耦合。

计量单位模块的重构

原设计:

clipboard.png

现设计:

clipboard.png

可以看出,我们这样重构计量单位模块,对其他模块的改动是最小的。

如果某个模块仅仅只依赖于这里的倍数,那该模块完全不知道计量单位模块已经被修改过了,因为计量单位模块对外的倍数表现是一致的。对其他模块的影响很小,这就是常说的松耦合。

单元测试

后台放心的改,只要单元测试过了就好。

没测试时,需要人为地去想我这里改会对其他模块造成什么影响,有时候还可能考虑不全,滋生新的问题。

级联

在这里不得不感叹一句,级联真的是太好用了!

clipboard.png

非强检器具类别: 参数类别 = 1: n

参数类别: 不确定度 = 1: n

设置两层级联,保存非强检器具类别时级联保存参数类别,保存参数类别时又级联保存不确定度,一个save方法就实现功能。

指令

写前台的时候能明显地感受到愉悦感与失落感:

想用一个计量单位的select,发现有指令了,特别开心。

然而发现重构计量单位的时候把这个指令重构坏了,伤心。

不得不去重写该指令,阅读别人的代码是很困难的,毕竟作者自己过了几个月都不知道自己写的是啥,还好晨澍的注释写得足够详尽,点个赞。

重写了几个指令之后发现之所以修改困难是因为不同人写指令的思路大相径庭,这不像ControllerService那样简单。

这里没法限制别人的思路,但是我可以自己定义一套规范,至少以后我重构自己写的指令时可以快速理解。

小例子

假设这里有一个test-directive的自定义指令,假设该指令的input是双向绑定的。

<test-directive input="test"></test-directive>

控制器代码:

self.init = function() {
    $scope.test = 'test';
};

self.init();

如果只是传一个普通的变量过去,这样在指令的init方法中是可以接受到的。

但是如果该数据是异步的话,那init中得到的就是undefined,所以需要对该数据进行监听,当不为undefined时再进行操作。

指令模板

所以如果是普通数据,如指令中的配置项,直接在init中进行获取,如果是异步数据,在init中对该数据添加监听。

数据更新使用响应式编程,写方法响应页面的各种事件,执行方法对数据进行更新。

clipboard.png

var self = this;

self.init = function() {
    // 定义计量单位缓存
    self.measurementUnits = [];
    // 初始化计量单位
    $scope.measurementUnits = [];
    // 获取计量单位列表
    self.getAllMeasurementUnits();
    // 监听计量单位类别
    $scope.$watch('measurementUnitCategory', self.watchCategory);
    // 监听计量单位
    $scope.$watch('ngModel', self.watchNgModel);
};

// 获取所有计量单位
self.getAllMeasurementUnits = function() {
    // 调用Service获取计量单位列表
    MeasurementUnitService.getAll(function(data) {
        // 保留缓存
        angular.copy(data, self.measurementUnits);
        // 传给视图
        $scope.measurementUnits = data;
    });
};

// 监听计量单位类别
self.watchCategory = function(newValue) {
    if (newValue && newValue.id) {
        // 过滤计量单位集合
        $scope.measurementUnits = self.measurementUnits.filter(function(value) {
            // 如果计量单位类别相同,保留
            if (value.measurementUnitCategory.id === newValue.id) {
                return true;
            } else {
                return false;
            }
        });
    }
};

// 监听计量单位
self.watchNgModel = function(newValue) {
    if (newValue && newValue.id) {
        // 默认选中
        $scope.selected = newValue;
    }
};

// 更新ngModel
self.updateModel = function(measurementUnit) {
    $scope.ngModel = measurementUnit;
};

$scope.updateModel = self.updateModel;

self.init();

弹窗

之前是使用晨澍写的ui-view改变路由实现弹窗,后台发现项目中的强检器具类别管理中已有弹窗相关实现,使用$uibModal,是UI-Bootstrap为我们提供的。

弹窗代码:

调用$uibModalopen方法生成一个弹窗。

// 弹出窗口初始化
self.modalInstance = function () {
    $uibModal.open({
        templateUrl: 'views/system/nonMandatoryInstrumentCategory/addEntity.html',
        size: 'small',
        controller: 'NonmandatoryinstrumentcategoryAddModalInstanceCtrl',
        scope: $scope
    });
};

clipboard.png

点击确定时,调用当前弹窗scope的父scopesaveAccuracyEntity方法将实体传过去。

// 提交实体
self.ok = function() {
    $scope.$parent.saveAccuracyEntity($scope.data, function() {
        // 关闭窗口
        $uibModalInstance.close();
    });
};

编辑

弹窗的编辑是一大问题,起初是想将对象传过去,看了之前的编辑,瞬间明白了。

clipboard.png

总结

需求变更鞭策着越来越优秀的软件设计。我们共同努力。


张喜硕
2.1k 声望423 粉丝

浅梦辄止,书墨未浓。