文档章节

代码重构那些事儿

JerryWang_SAP
 JerryWang_SAP
发布于 02/03 20:10
字数 1387
阅读 1
收藏 0

大家好,这是我今天演讲的目录,分Java,JavaScript,ABAP三门编程语言来讲述。

Java

•JAD •javap •Java Decompiler •Source Monitor •Visual VM •Refactor Menu in Eclipse

ABAP

•Code inspector •Refactor feature in AIE •Code coverage

JavaScript

•ESLint for Fiori Apps •Check Jenkins build log •JSlint for Sublime Text 2 •Code check in WebIDE •Profile in Chrome

在方法里引入一个布尔类型的参数控制方法的行为,这种做法正确吗?

看看stackoverflow上是怎么说的。

Java里定义常量的最佳实践:

http://developer.51cto.com/art/201509/492085.htm

Java里这两种定义常量的方法,哪种更好?

package one;
public interface Constants {
  String NAME = "孙悟空";
  int BP = 10000;
}

package two;

public class Constants {
   public static final String NAME = "贝吉塔";
   public static final int BP = 9000;
}

为什么我们不应该在Java 接口中使用Array:

https://eclipsesource.com/blogs/2014/04/11/3-good-reasons-to-avoid-arrays-in-java-interfaces

避免Array的原因之一:Array若使用不当,会造成性能问题

避免Array的原因之一:Array若使用不当,会造成性能问题

避免Array的原因之二:Array是面向过程编程领域的概念,使用Java面向对象的集合类,比如List,而不是Array

看个具体例子:

String[] array = { "乔布斯", "张小龙" };
List list = Arrays.asList( array );

System.out.println( list );
// 打印输出 [乔布斯, 张小龙]
System.out.println( array );
// -> [Ljava.lang.String;@6f548414

list.equals( Arrays.asList( "乔布斯", "张小龙" ) )
// -> true
array.equals( new String[] { "乔布斯", "张小龙" } )
// -> false

看出差距了吧?

Arrays不是类型安全的!

下面的代码能通过编译,但是运行时会报ArrayStoreException的异常:

Number[] numbers = new Integer[10];
numbers[0] = Long.valueOf( 0 ); 

而使用JDK的集合类比如List,就能在编译器即检测出这类错误。

Javascript里有趣的逗号

function a() {
  console.log("I was called!");
  return "Jerry";
}
var b = a(), a;

然后执行下面的代码:

console.log(b);

会打印出Jerry

再看这段代码:

var d = (function c(){
  return a(),a;
})();
console.log(d);

会打印出:

I was called!
function a() {
  console.log("I was called!");
  return "Jerry";
}

再看这段代码呢?

(function() {
    var e = f = 1;
})();

直接报错:Uncaught ReferenceError: f is not defined

JavaScript里有趣的分号

var b = function(para) {
  return {
  doSomething: function() {
  console.log("hello: " + para);
  return para;
  }
  }
}
var a = 1, x = 3, y = 4, s
s = a + b
(x + y).doSomething() // 打印出 hello: 7
console.log(s) // 打印出 8
function test(i){
  var result = i++;
  return
  result
}
console.log("test: " + test(3)) // 打印出undefined

继续看这段代码

s = function(x){ console.log("called: " + x ); return x}
(1 + 2).toString()

s = function(x){ console.log("called: " + x ); return x}(1 + 2).toString()

// 打印出 called: 3

小技巧 - 如何把您自己增强逻辑植入到legacy遗留代码中

var bigFunction = function() {
      // big logic
      console.log("big logic"); // 这句话模拟我们在一段很冗长的遗留代码里植入自己的新逻辑
}

// 下面这种解决方案不会直接修改遗留函数本身,显得比较优雅
var _old = bigFunction;
bigFunction = function() {
    if ( _old ) {
         _old();
    }
    console.log("our own enhancement");
}
bigFunction();

// 第三种解决方案采用了面向切片编程思想,显得更加高级
var bigFunction = function() {
  // big logic
  console.log("big logic");
}
bigFunction = ( bigFunction || function() {} ).after( function() {
     console.log("our own logic");
});
bigFunction();

如何优雅的在一个函数里增添性能测试统计的工具代码

var append_doms = function() {
    var d = new Date(); // dirty code - nothing to do with application logic!!!
    for( var i = 0; i < 100000; i++) {
      var div = document.createElement( "div");
        document.body.appendChild(div);
    }
    // dirty code - nothing to do with application logic!!!
    console.log(" time consumed: " + ( new Date() - d));
};
function test() {
  append_doms();
}

传统方案:在充满了业务逻辑的函数体里强行加入红色标准的搜集性能测试的工具代码,这个实现显得很丑陋:

再看看采用面向切片编程思路的解决方案:AOP - Aspect Oriented Programming

var append_doms = function() {
    for( var i = 0; i < 100000; i++) {
      var div = document.createElement( "div");
        document.body.appendChild(div);
    }
};

var log_time = function( func, log_name) {
       return func = ( function() {
           var d;
           return func.before( function(){
                 d = new Date();
           }).after( function(){
                 console.log( log_name + ( new Date() - d));
           });
     })();
 };

function test() {
 log_time(append_doms, "consumed time: ")();
}

如何避免代码中大量的IF - ELSE 检查

在调用真正的OData API之前,系统有大量的IF ELSE对API的输入参宿进行检查:

var send = function() {
     var value = input.value;
     if( value.length === '' ) {
           return false;
     }
     else if( value.length > MAX_LENGTH) {
           return false;
     }
     ... // lots of else
     else {
        // call OData API
     }
}

更优雅的解决方案:

把这些不同的检查规则封装到一个个JavaScript函数里,再把这些函数作为一个规则对象的属性:

var valid_rules = {
      not_empty: function( value ) {
         return value.length !== '';
      },
      max_length: function( value ) {
         return value.length <= MAX_LENGTH  ;
      }
 }

实现一个新的检查函数,变量检查对象的属性,执行校验逻辑:

var valid_check = function() {
     for( var i in valid_rules ) {
          if ( vali_rules[i].apply( this, arguments) === false ) {
                return false;
          }
     }
}

现在的OData调用函数非常优雅了:

var send = function( value ) {
       if ( valid_check( value ) === false ) {
             return;
       }
      // call OData API
}

通过这种方式消除了IF ELSE。

另一种通过职责链 Chain of Responsibility 的设计模式 design pattern消除IF ELSE分支的代码重构方式:

先看传统方式的实现:

// Priority: ActiveX > HTML5 > Flash > Form(default)
function isActiveXSupported(){
  //...
  return false;
}
function isHTML5Supported(){
  //...
  return false;
}
function isFlashSupported(){
  //...
  return false;
}

好多的IF -ELSE啊:

var uploadAPI;
if ( isActiveXSupported()) {
  // lots of initialization work
  uploadAPI = { "name": "ActiveX"};
}
else if( isHTML5Supported()) {
  // lots of initialization work
  uploadAPI = { "name": "HTML5"};
}
else if( isFlashSupported()) {
  // lots of initialization work
  uploadAPI = { "name": "Flash"};
}
else {
  // lots of initialization work
  uploadAPI = { "name": "Form"};
}
console.log(uploadAPI);

再看职责链设计模式的实现:

Chain of Responsibility

var getActiveX = function() {
  try {
  // lots of initialization work
  return { "name": "ActiveX"};
  }
  catch (e) {
  return null;
  }
}

var getHTML5 = function() {
  try {
  // lots of initialization work
  return { "name": "HTML5"};
  }
  catch (e) {
  return null;
  }
}

代码整洁优雅:

var uploadAPI = getActiveX.after(getHTML5).after(getFlash).after(getForm)();
console.log(uploadAPI);

Java中的String

public class stringTest {
public static void main(String[] args) {
  String userName = "Jerry";
  String skill = "JS";
  String job = "Developer";
  String info = userName + skill
     + job;
  System.out.println(info);
}
}

用javap将上面的Hello World程序反编译出来学习:

要获取更多Jerry的原创文章,请关注公众号"汪子熙":

© 著作权归作者所有

JerryWang_SAP
粉丝 24
博文 667
码字总数 531182
作品 0
深圳
程序员
私信 提问
1999年的ebay的软件代码到底是出了什么大事故

1999年的ebay的软件代码到底是出了什么大事故,每次看到代码重构的文章都拿这事儿来说

seandu
2015/06/15
614
4
什么是重构,什么不是重构

有时候,会有程序员跑到我这里说他们不喜欢某个东西的设计,“我们需要给它来个全面的重构”,来纠正里面的错误。哦,哦。这听起来可不是个好主意。而且这听起来也不是重构… 重构(Refactor...

景德真人
2012/05/14
2.7K
14
什么是重构,什么不是重构

有时候,会有程序员跑到我这里说他们不喜欢某个东西的设计,“我们需要给它来个全面的重构”,来纠正里面的错误。哦,哦。这听起来可不是个好主意。而且这听起来也不是重构… 重构(Refactor...

长平狐
2012/11/12
116
0
[转载]重构代码的7个阶段

你曾去想重构一个很老的模块,但是你只看了一眼你就恶心极了。文档,奇怪的函数和类的命名,等等,整个模块就像一个带着脚镣的衣衫褴褛的人,虽然能走,但是其已经让人感到很不舒服。面对这种...

长平狐
2013/06/17
65
0
重构 Git 分支

TL/DR (太长,请勿阅读) 本文中描述了允许一个人从一个较大的git分支中提取commit到独立的版本。“git版本重构(git branch refactoring)”提供了许多好处: 快速跟踪那些整合的紧迫变化(...

oschina
2014/05/01
558
0

没有更多内容

加载失败,请刷新页面

加载更多

java数据类型

基本类型: 整型:Byte,short,int,long 浮点型:float,double 字符型:char 布尔型:boolean 引用类型: 类类型: 接口类型: 数组类型: Byte 1字节 八位 -128 -------- 127 short 2字节...

audience_1
34分钟前
5
0
太全了|万字详解Docker架构原理、功能及使用

一、简介 1、了解Docker的前生LXC LXC为Linux Container的简写。可以提供轻量级的虚拟化,以便隔离进程和资源,而且不需要提供指令解释机制以及全虚拟化的其他复杂性。相当于C++中的NameSpa...

Java技术剑
35分钟前
8
0
Wifiphisher —— 非常非常非常流氓的 WIFI 网络钓鱼框架

编者注:这是一个非常流氓的 WIFI 网络钓鱼工具,甚至可能是非法的工具(取决于你的使用场景)。在没有事先获得许可的情况下使用 Wifiphisher 攻击基础网络设施将被视为非法活动。使用时请遵...

红薯
今天
46
1
MongoDB 4 on CentOS 7安装指南

本教程为CentOS x86_64 7.x操作系统下,MongoDB Community x86_64 4.2(GA)安装指南。 安装方式一:yum repo在线安装 [此方式较为简单,官方推荐] Step1:新建MongDB社区版Yum镜像源。 # vim ...

王焱君
今天
7
0
go-micro 入门教程1.搭建 go-micro环境

微服务的本质是让专业的人做专业的事情,做出更好的东西。 golang具备高并发,静态编译等特性,在性能、安全等方面具备非常大的优势。go-micro是基于golang的微服务编程框架,go-micro操作简单...

非正式解决方案
今天
11
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部