一文看懂印度原油经济的弱点 原油市场是否是救命稻草

必须推荐&br&&a href=&//link.zhihu.com/?target=http%3A//v.youku.com/v_show/id_XNDE3NzAxMTg4.html%3Ffrom%3Dy1.7-2& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&额外加分 Extra Credits EP28: 像游戏策划一样的玩游戏(上)&/a&&br&&a href=&//link.zhihu.com/?target=http%3A//v.youku.com/v_show/id_XNDIxMzk5NzQw.html%3Ffrom%3Dy1.7-2& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&额外加分 Extra Credits EP29: 像策划一样玩游戏 (下)&/a&
&--------- Modified at
start ---------&&br&以下是关于重构的个人书单。&br&两本就够了,别的都大同小异,有兴趣的朋友可以去读读:&br&&a href=&//link.zhihu.com/?target=http%3A//www.amazon.cn/gp/product/B0031M9GHC%3Fkeywords%3D%25E4%25BB%25A3%25E7%25A0%%%25E6%25B4%%25B9%258B%25E9%qid%3D%26ref_%3Dsr_1_1%26sr%3D8-1& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&代码整洁之道&/a&&br&&a href=&//link.zhihu.com/?target=http%3A//www.amazon.cn/%25E9%E6%259E%%%25E5%E6%%25E6%259C%%25BB%25A3%25E7%25A0%%259A%%25AE%25BE%25E8%25AE%25A1-%25E9%25A9%25AC%25E4%25B8%%25B7%25E7%25A6%258F%25E5%258B%2592/dp/B011LPUB42/ref%3Dsr_1_1%3Fs%3Dbooks%26ie%3DUTF8%26qid%3D%26sr%3D1-1%26keywords%3D%25E9%E6%259E%E6%%25E5%E6%%25E6%259C%%25BB%25A3%25E7%25A0%%259A%%25AE%25BE%25E8%25AE%25A1& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&重构:改善既有代码的设计&/a&&br&&--------- Modified at
end ---------&&br&&br&&--------- Modified at
start ---------&&br&&br&有朋友知道怎么开专栏么?想在知乎找块地专门谈谈代码的那些事儿。&br&&--------- Modified at
end ---------&&br&&br&题主,我来告诉你解决你目前困境的不二法门。不要说区区五六百行的程序,再大到上W行的代码,都可以&b&让你满怀信心&/b&的解决。这个法门就叫做--&b&重构&/b&。&br&不用担心,它是有方法论的。只要你按下面的步骤,&b&小步修改,确保每次修改后通过测试&/b&。我保证:&br&&blockquote&变量众多,再牵涉到相互之间的逻辑&br&&/blockquote&1.你会对这500多行代码的整体结构一目了然,豁然开朗;&br&&br&&blockquote&生怕某个地方改错,导致不可知的错误&/blockquote&2.对每一次修改都充满信心,对它的影响范围都了如指掌,不担心会引起代码的degree;&br&&br&接下来开始我们的重构:&br&&b&&u&1.给每一个变量和函数重命名&/u&&/b&&br&&b&重命名的方法是,让每一个变量或函数的意义明确,一目了然。&/b&&br&
如果你看到一个i,不要默认它是循环变量,给它取一个有意思的名字;&br&
如果你想给“对战”取一个变量名,不要这么写:dz。如果你写成fight,下一个读代码的人会对你感激不尽;&br&
如果insert函数是插入成绩,那么insertScore是一个更合适的函数名称;&br&
如果你的函数里,做了成绩查询和修改处理,那么用retrieveAndModifyScore来命名它;&br&
做完如此之后,如果你发现乃至&b&所有的注释都是多此一举&/b&,那么恭喜你:Well done!&br&&br&&i&&b&然后Run -& Test,谨小慎微的确保我们的该步操作大功告成。&/b&&/i&&br&&br& 接下来我们深入函数的内部,厘清那些让我们力不从心的复杂逻辑。&br&&u&&b&
2.改写if else逻辑&/b&&/u&&br&
繁多的if else,if中的if else,else中if else,这些庞大的逻辑块看上去就让人云山雾绕,那是是时候祭出重构公式来简化它了。&br&
重构的思路为:if和else的逻辑我们只能二选其一。&br&
对于if,我们可在if的逻辑块里加上一个return,表明我们执行完if之后,不再涉及else的代码。&br&
对于else,由于之前一部已确保if的逻辑执行后会返回,我们大可放心的将else的代码提出来,去掉else这个关键字。&br&
话不多说,直接上例子:&br&&div class=&highlight&&&pre&&code class=&language-java&&&span class=&k&&if&/span& &span class=&o&&(&/span& &span class=&n&&m_Prop&/span&&span class=&o&&.&/span&&span class=&na&&A&/span& &span class=&o&&==&/span& &span class=&mi&&1&/span& &span class=&o&&)&/span&
&span class=&o&&{&/span&
&span class=&k&&if&/span& &span class=&o&&(&/span& &span class=&n&&m_Prop&/span&&span class=&o&&.&/span&&span class=&na&&B&/span& &span class=&o&&==&/span& &span class=&mi&&1&/span& &span class=&o&&)&/span&
&span class=&o&&{&/span&
&span class=&k&&return&/span& &span class=&s&&&Good&&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span&
&span class=&k&&else&/span& &span class=&k&&if&/span& &span class=&o&&(&/span& &span class=&n&&m_Prop&/span&&span class=&o&&.&/span&&span class=&na&&B&/span& &span class=&o&&==&/span& &span class=&mi&&2&/span& &span class=&o&&)&/span&
&span class=&o&&{&/span&
&span class=&k&&return&/span& &span class=&s&&&Not too bad&&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span&
&span class=&k&&else&/span& &span class=&k&&return&/span& &span class=&s&&&Just so so&&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span&
&span class=&k&&else&/span& &span class=&k&&if&/span& &span class=&o&&(&/span& &span class=&n&&m_Prop&/span&&span class=&o&&.&/span&&span class=&na&&A&/span& &span class=&o&&==&/span& &span class=&mi&&2&/span& &span class=&o&&)&/span&
&span class=&o&&{&/span&
&span class=&k&&if&/span& &span class=&o&&(&/span& &span class=&n&&m_Prop&/span&&span class=&o&&.&/span&&span class=&na&&B&/span& &span class=&o&&==&/span& &span class=&mi&&1&/span& &span class=&o&&)&/span&
&span class=&o&&{&/span&
&span class=&k&&if&/span& &span class=&o&&(&/span& &span class=&n&&m_Prop&/span&&span class=&o&&.&/span&&span class=&na&&C&/span& &span class=&o&&==&/span& &span class=&mi&&1&/span& &span class=&o&&)&/span&
&span class=&o&&{&/span&
&span class=&k&&return&/span& &span class=&s&&&Need improvement&&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span&
&span class=&k&&else&/span& &span class=&k&&return&/span& &span class=&s&&&Need more improvement&&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span&
&span class=&k&&else&/span& &span class=&k&&if&/span& &span class=&o&&(&/span& &span class=&n&&m_Prop&/span&&span class=&o&&.&/span&&span class=&na&&B&/span& &span class=&o&&==&/span& &span class=&mi&&2&/span& &span class=&o&&)&/span&
&span class=&o&&{&/span&
&span class=&k&&return&/span& &span class=&s&&&Have a chance to improve&&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span&
&span class=&k&&else&/span& &span class=&k&&return&/span& &span class=&s&&&Too bad&&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span&
&/code&&/pre&&/div&这是一段重构前的代码,每每看到这里,都有一种给跪了的感觉。&br&于是第一步的重构开始了,我们的第一次,就从 else if ( m_Prop.A == 2 )开始,从去掉else开始。&br&这次重构后的代码如下,是一次简单的不能再简单的修改。&br&&div class=&highlight&&&pre&&code class=&language-java&&&span class=&k&&if&/span& &span class=&o&&(&/span& &span class=&n&&m_Prop&/span&&span class=&o&&.&/span&&span class=&na&&A&/span& &span class=&o&&==&/span& &span class=&mi&&1&/span& &span class=&o&&){&/span&
&span class=&k&&if&/span& &span class=&o&&(&/span& &span class=&n&&m_Prop&/span&&span class=&o&&.&/span&&span class=&na&&B&/span& &span class=&o&&==&/span& &span class=&mi&&1&/span& &span class=&o&&)&/span&
&span class=&o&&{&/span&
&span class=&k&&return&/span& &span class=&s&&&Good&&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span&
&span class=&k&&else&/span& &span class=&k&&if&/span& &span class=&o&&(&/span& &span class=&n&&m_Prop&/span&&span class=&o&&.&/span&&span class=&na&&B&/span& &span class=&o&&==&/span& &span class=&mi&&2&/span& &span class=&o&&)&/span&
&span class=&o&&{&/span&
&span class=&k&&return&/span& &span class=&s&&&Not too bad&&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span&
&span class=&k&&else&/span& &span class=&k&&return&/span& &span class=&s&&&Just so so&&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span&
&span class=&k&&if&/span& &span class=&o&&(&/span& &span class=&n&&m_Prop&/span&&span class=&o&&.&/span&&span class=&na&&A&/span& &span class=&o&&==&/span& &span class=&mi&&2&/span& &span class=&o&&)&/span&
&span class=&o&&{&/span&
&span class=&k&&if&/span& &span class=&o&&(&/span& &span class=&n&&m_Prop&/span&&span class=&o&&.&/span&&span class=&na&&B&/span& &span class=&o&&==&/span& &span class=&mi&&1&/span& &span class=&o&&)&/span&
&span class=&o&&{&/span&
&span class=&k&&if&/span& &span class=&o&&(&/span& &span class=&n&&m_Prop&/span&&span class=&o&&.&/span&&span class=&na&&C&/span& &span class=&o&&==&/span& &span class=&mi&&1&/span& &span class=&o&&)&/span&
&span class=&o&&{&/span&
&span class=&k&&return&/span& &span class=&s&&&Need improvement&&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span&
&span class=&k&&else&/span& &span class=&k&&return&/span& &span class=&s&&&Need more improvement&&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span&
&span class=&k&&else&/span& &span class=&k&&if&/span& &span class=&o&&(&/span& &span class=&n&&m_Prop&/span&&span class=&o&&.&/span&&span class=&na&&B&/span& &span class=&o&&==&/span& &span class=&mi&&2&/span& &span class=&o&&)&/span&
&span class=&o&&{&/span&
&span class=&k&&return&/span& &span class=&s&&&Have a chance to improve&&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span&
&span class=&k&&else&/span& &span class=&k&&return&/span& &span class=&s&&&Too bad&&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span&
&/code&&/pre&&/div&以此类推的重构后,得到如下代码:&br&&br&&div class=&highlight&&&pre&&code class=&language-java&&&span class=&k&&if&/span& &span class=&o&&(&/span& &span class=&n&&m_Prop&/span&&span class=&o&&.&/span&&span class=&na&&A&/span& &span class=&o&&==&/span& &span class=&mi&&1&/span& &span class=&o&&){&/span&
&span class=&k&&if&/span& &span class=&o&&(&/span& &span class=&n&&m_Prop&/span&&span class=&o&&.&/span&&span class=&na&&B&/span& &span class=&o&&==&/span& &span class=&mi&&1&/span& &span class=&o&&)&/span&
&span class=&o&&{&/span&
&span class=&k&&return&/span& &span class=&s&&&Good&&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span&
&span class=&k&&if&/span& &span class=&o&&(&/span& &span class=&n&&m_Prop&/span&&span class=&o&&.&/span&&span class=&na&&B&/span& &span class=&o&&==&/span& &span class=&mi&&2&/span& &span class=&o&&)&/span&
&span class=&o&&{&/span&
&span class=&k&&return&/span& &span class=&s&&&Not too bad&&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span&
&span class=&k&&return&/span& &span class=&s&&&Just so so&&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span&
&span class=&k&&if&/span& &span class=&o&&(&/span& &span class=&n&&m_Prop&/span&&span class=&o&&.&/span&&span class=&na&&A&/span& &span class=&o&&==&/span& &span class=&mi&&2&/span& &span class=&o&&)&/span&
&span class=&o&&{&/span&
&span class=&k&&if&/span& &span class=&o&&(&/span& &span class=&n&&m_Prop&/span&&span class=&o&&.&/span&&span class=&na&&B&/span& &span class=&o&&==&/span& &span class=&mi&&1&/span& &span class=&o&&)&/span&
&span class=&o&&{&/span&
&span class=&k&&if&/span& &span class=&o&&(&/span& &span class=&n&&m_Prop&/span&&span class=&o&&.&/span&&span class=&na&&C&/span& &span class=&o&&==&/span& &span class=&mi&&1&/span& &span class=&o&&)&/span&
&span class=&o&&{&/span&
&span class=&k&&return&/span& &span class=&s&&&Need improvement&&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span&
&span class=&k&&return&/span& &span class=&s&&&Need more improvement&&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span&
&span class=&k&&if&/span& &span class=&o&&(&/span& &span class=&n&&m_Prop&/span&&span class=&o&&.&/span&&span class=&na&&B&/span& &span class=&o&&==&/span& &span class=&mi&&2&/span& &span class=&o&&)&/span&
&span class=&o&&{&/span&
&span class=&k&&return&/span& &span class=&s&&&Have a chance to improve&&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span&
&span class=&k&&return&/span& &span class=&s&&&Too bad&&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span&
&/code&&/pre&&/div&&br&
如果&b&重构后的代码再也不见else,而逻辑上你很清楚与重构前相等&/b&,那么恭喜你,这一步也完成了!&br&&br&&i&&b&在每一次if else的修改后,&/b&&/i&&i&&b&Run -& Test,谨小慎微的确保我们的该步操作大功告成。&/b&&/i&&br&&br&&br&&i&--------------------------------------&/i&&i&----&/i&&i&--&/i&更新于&i&--------------------------------------&/i&&i&----&/i&&i&--&/i&&br&&br&感谢大家热情的反馈。上周因为换工作的事没来得及更新,换工作后白天也不能上外网,我将尽量利用晚上的时间,在这周之内更完余下的部分。&br&今天探讨的是&b&去除重复&/b&。&br&&br&言归正传之前,继续说说 2.改写if else逻辑。&br&记得大学学谭总的C语言,教材上仿佛提到过:一个函数只能有一个出口。前面提到if之后立即return,似乎有违此理。&br&好在这么写并不违背语法,于是我也可以斗胆谈谈这么做的初衷:&br&1.可读性&br&当函数中出现任一一个return,即意味着这个分支到此为止。这样一个个return,将一块块的逻辑分支分段。读代码的人只需专心理解每一段的逻辑,而不必耗费精力,深挖该段逻辑之后是否还有额外的处理--因为我们的代码已经return了。&br&2.避免误修改&br&诚然我们可以在每个分支的结尾,将返回值赋值给一个新的变量,在函数的末尾返回这个变量。这样做保证了函数只有一次返回,并且该处还可以做一些诸如异常捕捉的统一处理。 &br&但是,但是这就没法保证,这个作为返回值的变量,不会在后续的处理中被意外的修改。俗话说夜长梦多,个人建议还是该出手时就出手,能返回时就返回。&br&&br&关于这个话题,最后还是将评论里&a href=&http://www.zhihu.com/people/tianzihou& class=&internal&&侯天资&/a&兄的评论借花献佛:&br&&blockquote&进入enum用switch-case逻辑模块+带现实意义的常量作为case的值进行捕捉和处理,这个也会比==1, !=2, &=3这种if-else的逻辑判断的可读性好得多得多&br&&/blockquote&即使小小的if-else也需要我们足够努力,才能让读代码的人读的不费吹灰之力。&br&&br&写到这里,想请大家思考个问题:当我们要做什么的时候,我们会想到if-else / switch?&br&是否我们是想基于不同的业务触发条件,来做不同的数据处理?亦或是判断对象的不同状态,来调用它不同的行为响应?&br&好吧,我想各位已经明白我想表达的。不明白的话,可以看看多态的定义。&br&有人的地方就有江湖,有分支的地方就可能改为多态。&br&关于这个话题,后面有机会再行展开。&br&&br&当逻辑分支重构得不那么令人头疼的时候,我们来说说最令代码修改者闻风丧胆、谈之色变的问题--代码重复。&br&&u&&b&3.去除重复代码&/b&&/u&&br&过往的项目经验里,最让人头疼的便是修改重复代码,无论是因为需求变更,还是因为bug修改。当你用着关键字,一遍遍的CTRL+F,将找到之处再一遍遍的用类似的代码替换时,是否已经精疲力尽?更糟糕的是,你还会担心这样的查找,会不会有漏网之鱼。在某个可能无法用关键字找出的角落,会不会还有类似需要修改的地方,让你担惊受怕?&br&遗憾的是,很多programmer意识不到这样的无用功是因为代码重复产生的。&b&当一行行的代码用CTRL+C、CTRL+V的方式产生时,恶趣味的重复代码就注定生成了。&/b&&br&&b&将重复的代码块浓缩为函数,使用一次就调用一次这个函数,直到&/b&&b&找不出类似代码&/b&。&br&&br&我相信有时候并不是程序员不知道如何解决前文提到的困扰,他们只是缺乏这么做的信心和勇气。&br&想想终将修改这些重复代码时,你的疲乏和担心。反正都要一个个的修改,何不如一个个的替换为函数。&i&&b&用函数代替重复代码块,Run -& Test,替换一处就测试一次,直到全部的重复代码都变为函数调用。&/b&&/i&&br&&br&&br&&br&&i&--------------------------------------&/i&&i&----&/i&&i&--&/i&更新于&i&--------------------------------------&/i&&i&----&/i&&i&--&/i&&br&完成了变量、代码块的重构后,接下来谈谈如何重构一个函数。&br&&b&&u&4.让函数只做一件事情&/u&&/b&&br&我大学刚开始写C代码时,脑子里充满了如果XXX,就XXX,然后XXX的逻辑思维。&br&翻译成C语言,就是main里面一大段一气呵成的代码。后来觉着这样不对啊:没用到函数啊!于是乎将相关又相邻的代码提炼出来,取一个函数名,函数调用一用上,大功告成!&br&就好像下面这个修改密码的函数,咋一看逻辑清楚,似乎也没啥大问题:&br&&div class=&highlight&&&pre&&code class=&language-java&&&span class=&kd&&public&/span& &span class=&n&&Boolean&/span& &span class=&nf&&ChangePassword&/span&&span class=&o&&(&/span&&span class=&kt&&int&/span& &span class=&n&&id&/span&&span class=&o&&,&/span& &span class=&n&&String&/span& &span class=&n&&oldPassword&/span&&span class=&o&&,&/span& &span class=&n&&String&/span& &span class=&n&&newPassword&/span&&span class=&o&&)&/span& &span class=&o&&{&/span&
&span class=&n&&oldPassword&/span& &span class=&o&&=&/span& &span class=&n&&EncodeHelper&/span&&span class=&o&&.&/span&&span class=&na&&MD5&/span&&span class=&o&&(&/span&&span class=&n&&oldPassword&/span&&span class=&o&&.&/span&&span class=&na&&trim&/span&&span class=&o&&());&/span&
&span class=&n&&newPassword&/span& &span class=&o&&=&/span& &span class=&n&&EncodeHelper&/span&&span class=&o&&.&/span&&span class=&na&&MD5&/span&&span class=&o&&(&/span&&span class=&n&&newPassword&/span&&span class=&o&&.&/span&&span class=&na&&trim&/span&&span class=&o&&());&/span&
&span class=&k&&if&/span& &span class=&o&&(!&/span&&span class=&n&&oldPassword&/span&&span class=&o&&.&/span&&span class=&na&&Equals&/span&&span class=&o&&(&/span&&span class=&k&&this&/span&&span class=&o&&.&/span&&span class=&na&&GetStudent&/span&&span class=&o&&(&/span&&span class=&n&&id&/span&&span class=&o&&).&/span&&span class=&na&&LoginPassword&/span&&span class=&o&&))&/span& &span class=&o&&{&/span&
&span class=&k&&return&/span& &span class=&kc&&false&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span&
&span class=&k&&return&/span& &span class=&k&&this&/span&&span class=&o&&.&/span&&span class=&na&&UpdateStudent&/span&&span class=&o&&(&/span&&span class=&k&&new&/span& &span class=&n&&Student&/span&&span class=&o&&(&/span&&span class=&n&&id&/span&&span class=&o&&,&/span& &span class=&n&&newPassword&/span&&span class=&o&&));&/span&
&span class=&o&&}&/span&
&/code&&/pre&&/div&&br&可是,若后续要修改密码的验证逻辑,我们还能否记得,在ChangePassword的函数里,留有一行小小的if语句必须修改?&br&&b&重构函数的方法,也是函数分割的基准:一个函数一次只能做一件事。&/b&&br&而一个函数一次能做的,有且仅有下面三件事~~之一:&br&&b&1.查询&/b&&br&&b&2.修改&/b&&br&&b&3.调用上述两个过程&/b&&br&按照这个思路,重构上面的代码:&br&&div class=&highlight&&&pre&&code class=&language-java&&&span class=&kd&&public&/span& &span class=&n&&Boolean&/span& &span class=&nf&&ChangePassword&/span&&span class=&o&&(&/span&&span class=&kt&&int&/span& &span class=&n&&id&/span&&span class=&o&&,&/span& &span class=&n&&String&/span& &span class=&n&&oldPassword&/span&&span class=&o&&,&/span& &span class=&n&&String&/span& &span class=&n&&newPassword&/span&&span class=&o&&){&/span&
&span class=&k&&if&/span&&span class=&o&&(&/span&&span class=&k&&this&/span&&span class=&o&&.&/span&&span class=&na&&ValidateOldPassword&/span&&span class=&o&&(&/span&&span class=&n&&id&/span&&span class=&o&&,&/span& &span class=&n&&oldPassword&/span&&span class=&o&&))&/span& &span class=&o&&{&/span&
&span class=&k&&return&/span& &span class=&k&&this&/span&&span class=&o&&.&/span&&span class=&na&&SaveNewPassword&/span&&span class=&o&&(&/span&&span class=&n&&id&/span&&span class=&o&&,&/span& &span class=&n&&newPassword&/span&&span class=&o&&);&/span&
&span class=&o&&}&/span&
&span class=&k&&return&/span& &span class=&kc&&false&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span&
&span class=&kd&&private&/span& &span class=&n&&Boolean&/span& &span class=&nf&&ValidateOldPassword&/span&&span class=&o&&(&/span&&span class=&kt&&int&/span& &span class=&n&&id&/span&&span class=&o&&,&/span& &span class=&n&&String&/span& &span class=&n&&oldPassword&/span&&span class=&o&&){&/span&
&span class=&n&&oldPassword&/span& &span class=&o&&=&/span& &span class=&n&&EncodeHelper&/span&&span class=&o&&.&/span&&span class=&na&&MD5&/span&&span class=&o&&(&/span&&span class=&n&&oldPassword&/span&&span class=&o&&.&/span&&span class=&na&&trim&/span&&span class=&o&&());&/span&
&span class=&k&&return&/span& &span class=&n&&oldPassword&/span&&span class=&o&&.&/span&&span class=&na&&Equals&/span&&span class=&o&&(&/span&&span class=&k&&this&/span&&span class=&o&&.&/span&&span class=&na&&GetStudent&/span&&span class=&o&&(&/span&&span class=&n&&id&/span&&span class=&o&&).&/span&&span class=&na&&LoginPassword&/span&&span class=&o&&);&/span&
&span class=&o&&}&/span&
&span class=&kd&&private&/span& &span class=&n&&Boolean&/span& &span class=&nf&&SaveNewPassword&/span&&span class=&o&&(&/span&&span class=&kt&&int&/span& &span class=&n&&id&/span&&span class=&o&&,&/span& &span class=&n&&String&/span& &span class=&n&&newPassword&/span&&span class=&o&&){&/span&
&span class=&n&&newPassword&/span& &span class=&o&&=&/span& &span class=&n&&EncodeHelper&/span&&span class=&o&&.&/span&&span class=&na&&MD5&/span&&span class=&o&&(&/span&&span class=&n&&newPassword&/span&&span class=&o&&.&/span&&span class=&na&&trim&/span&&span class=&o&&());&/span&
&span class=&k&&return&/span& &span class=&k&&this&/span&&span class=&o&&.&/span&&span class=&na&&UpdateStudent&/span&&span class=&o&&((&/span&&span class=&k&&new&/span& &span class=&n&&Student&/span&&span class=&o&&(&/span&&span class=&n&&id&/span&&span class=&o&&,&/span& &span class=&n&&newPassword&/span&&span class=&o&&)));&/span&
&span class=&o&&}&/span&
&/code&&/pre&&/div&&br&完成上述重构后,&b&每个函数体中的代码逻辑,一定是围绕着函数名所示的功能,绝无多余。&/b&&br&函数一次只做一件事,至少有如下2点好处:&br&1.可读性强&br&
我们甚至不用深入函数体,只浏览函数名就能理解其逻辑意义。&br&2.便于维护修改&br&
上面的例子中,若要修改密码的验证逻辑,我们只需修改ValidateOldPassword()即可。&br&&br&此外,功能单一,划分维度细小的函数也有助于发现代码中的漏洞。&br&例如下面的代码展示了一个游戏在服务器端,是如何返回PVP画面显示用的JSON:&br&&div class=&highlight&&&pre&&code class=&language-java&&&span class=&c1&&//fightHistories:从PVP表中获得的记录列表&/span&
&span class=&kd&&public&/span& &span class=&n&&String&/span& &span class=&nf&&getPVPResult&/span&&span class=&o&&(&/span&&span class=&kt&&int&/span& &span class=&n&&userId&/span&&span class=&o&&,&/span& &span class=&kt&&int&/span& &span class=&n&&rivalId&/span&&span class=&o&&,&/span& &span class=&n&&List&/span&&span class=&o&&&&/span&&span class=&n&&FightHistoryDao&/span&&span class=&o&&&&/span& &span class=&n&&fightHistories&/span&&span class=&o&&){&/span&
&span class=&n&&String&/span& &span class=&n&&myProfile&/span& &span class=&o&&=&/span& &span class=&n&&getMyProfile&/span&&span class=&o&&(&/span&&span class=&n&&userId&/span&&span class=&o&&);&/span&
&span class=&n&&String&/span& &span class=&n&&rivalProfile&/span& &span class=&o&&=&/span& &span class=&n&&getRivalProfile&/span&&span class=&o&&(&/span&&span class=&n&&rivalId&/span&&span class=&o&&);&/span&
&span class=&n&&String&/span& &span class=&n&&fightHistory&/span& &span class=&o&&=&/span& &span class=&n&&getFightHistories&/span&&span class=&o&&(&/span&&span class=&n&&fightHistories&/span&&span class=&o&&);&/span&
&span class=&k&&return&/span& &span class=&n&&generateJsonForPVPResult&/span&&span class=&o&&(&/span&&span class=&n&&myProfile&/span&&span class=&o&&,&/span& &span class=&n&&rivalProfile&/span&&span class=&o&&,&/span& &span class=&n&&fightHistory&/span&&span class=&o&&);&/span&
&span class=&o&&}&/span&
&span class=&kd&&private&/span& &span class=&n&&String&/span& &span class=&nf&&getFightHistories&/span&&span class=&o&&(&/span&&span class=&n&&List&/span&&span class=&o&&&&/span&&span class=&n&&FightHistoryDao&/span&&span class=&o&&&&/span& &span class=&n&&fightHistoryDaos&/span&&span class=&o&&){&/span&
&span class=&k&&for&/span&&span class=&o&&(&/span&&span class=&n&&FightHistoryDao&/span& &span class=&n&&oneFightScore&/span& &span class=&n&&in&/span& &span class=&n&&fightHistoryDaos&/span&&span class=&o&&)&/span& &span class=&o&&{&/span&
&span class=&c1&&//{取得对战时间}&/span&
&span class=&c1&&//{取得转化为百分数后的分数}&/span&
&span class=&c1&&//{取得作战详细}&/span&
&span class=&o&&}&/span&
&/code&&/pre&&/div&这段代码若是按照上述的方法进行重构分析,在第1和第4步是能够发现潜在的漏洞的:&br&&blockquote&在getFightHistories()中,{取得转化为百分数后的分数}做了不止一件事:&br&既将画面显示用的分数取出,做了格式转换;&br&同时由于oneFightScore是List中的一个对象,因而悄无声息地修改了fightHistories中记录的值。&/blockquote&&p&getFightHistories这个函数既查询了数据,又修改了数据。更糟糕的是,单单看这个函数名,我们很难想到它修改了fightHistories。&/p&&p&若后续代码修改,调用getFightHistories之后,再次使用了已被修改过的fightHistories变量,产生不可预料的结果就不足为奇了。&/p&&p&为了避免上述问题,请严格按照&b&一次只做一事的标准分割函数&/b&,并且参数传递时&b&尽量使用immutable变量&/b&。&/p&&br&&p&&i&&b&然后Run -& Test,保证每分割出一个函数,中间的调用和返回都准确无误。&/b&&/i&&/p&&br&&p&&i&--------------------------------------&/i&&i&----&/i&&i&--&/i&更新于&i&--------------------------------------&/i&&i&----&/i&&i&--&/i&&br&&/p&&p&&b&&u&5.减少函数参数&/u&&/b&&/p&&p&公用函数的参数越多,调用时了解的细节必须越多,不利于函数的公用;&br&&/p&&p&另一方面,参数越多也就意味着变数越大。当与传参有关的逻辑发生变化时,拥有多个参数的函数,总是让人顾虑重重。&/p&&p&减少函数参数具体的办法有:&/p&&p&①函数参数 -& context变量(如cookie、session)&/p&&p&②函数参数 -& TABLE字段&/p&&p&③&b&函数参数&/b&&b& -& 提取类参&/b&&/p&&p&④&b&函数参数&/b&&b& -& 公共变量&/b&&/p&&p&这里主要讲讲③和④,&br&&/p&&p&所谓类参,就是将‘类“作为参数。比如说代码里,有多个函数都有&b&一些固定搭配的参数,就可以将他们组合成一个类(或结构体)&/b&,从而达到减少参数的目的。&/p&&p&例如你在不止一个函数调用中见到过id、password这种搭配。那么就可以将他们组成一个类,取一个合适的名字,如user。&/p&&p&俗话说不是一家人,不进一家门。这几个参数既然搭配出现,不如就让他们在一起吧。&/p&&br&&p&至于第④点:公共变量。以上面重构后的代码为例,目前重构后的代码有三个函数,分别为:&/p&&div class=&highlight&&&pre&&code class=&language-java&&&span class=&kd&&public&/span& &span class=&n&&Boolean&/span& &span class=&nf&&ChangePassword&/span&&span class=&o&&(&/span&&span class=&kt&&int&/span& &span class=&n&&id&/span&&span class=&o&&,&/span& &span class=&n&&String&/span& &span class=&n&&oldPassword&/span&&span class=&o&&,&/span& &span class=&n&&String&/span& &span class=&n&&newPassword&/span&&span class=&o&&)&/span&
&span class=&kd&&private&/span& &span class=&n&&Boolean&/span& &span class=&nf&&ValidateOldPassword&/span&&span class=&o&&(&/span&&span class=&kt&&int&/span& &span class=&n&&id&/span&&span class=&o&&,&/span& &span class=&n&&String&/span& &span class=&n&&oldPassword&/span&&span class=&o&&)&/span&
&span class=&kd&&private&/span& &span class=&n&&Boolean&/span& &span class=&nf&&SaveNewPassword&/span&&span class=&o&&(&/span&&span class=&kt&&int&/span& &span class=&n&&id&/span&&span class=&o&&,&/span& &span class=&n&&String&/span& &span class=&n&&newPassword&/span&&span class=&o&&)&/span&
&/code&&/pre&&/div&&p&这三个函数的参数虽然各有不同,但实质都是围绕三个变量来处理:&/p&&p&int id, String oldPassword, String newPassword&/p&&p&因此我们将这三个&b&参数作为公共变量提取出来,改为类变量。将使用这些参数的函数作为类的方法,去掉函数参数,改为直接使用类变量&/b&。重构后的代码为:&/p&&br&&div class=&highlight&&&pre&&code class=&language-java&&&span class=&kd&&public&/span& &span class=&kd&&class&/span& &span class=&nc&&Student&/span& &span class=&o&&{&/span&
&span class=&kd&&private&/span& &span class=&kt&&int&/span& &span class=&n&&id&/span&&span class=&o&&;&/span&
&span class=&kd&&private&/span& &span class=&n&&String&/span& &span class=&n&&oldPassword&/span&&span class=&o&&;&/span&
&span class=&kd&&private&/span& &span class=&n&&String&/span& &span class=&n&&newPassword&/span&&span class=&o&&;&/span&
&span class=&kd&&public&/span& &span class=&nf&&Student&/span&&span class=&o&&(&/span&&span class=&kt&&int&/span& &span class=&n&&id&/span&&span class=&o&&,&/span& &span class=&n&&String&/span& &span class=&n&&password&/span&&span class=&o&&)&/span& &span class=&o&&{&/span&
&span class=&k&&this&/span&&span class=&o&&.&/span&&span class=&na&&id&/span& &span class=&o&&=&/span& &span class=&n&&id&/span&&span class=&o&&;&/span&
&span class=&k&&this&/span&&span class=&o&&.&/span&&span class=&na&&oldPassword&/span& &span class=&o&&=&/span& &span class=&n&&password&/span&&span class=&o&&;&/span&
&span class=&k&&this&/span&&span class=&o&&.&/span&&span class=&na&&newPassword&/span& &span class=&o&&=&/span& &span class=&n&&password&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span&
&span class=&kd&&public&/span& &span class=&n&&Boolean&/span& &span class=&nf&&ChangePassword&/span&&span class=&o&&(){&/span&
&span class=&k&&if&/span&&span class=&o&&(&/span&&span class=&n&&ValidateOldPassword&/span&&span class=&o&&())&/span& &span class=&o&&{&/span&
&span class=&k&&return&/span& &span class=&n&&SaveNewPassword&/span&&span class=&o&&();&/span&
&span class=&o&&}&/span&
&span class=&k&&return&/span& &span class=&kc&&false&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span&
&span class=&kd&&private&/span& &span class=&n&&Boolean&/span& &span class=&nf&&ValidateOldPassword&/span&&span class=&o&&(){&/span&
&span class=&n&&oldPassword&/span& &span class=&o&&=&/span& &span class=&n&&EncodeHelper&/span&&span class=&o&&.&/span&&span class=&na&&MD5&/span&&span class=&o&&(&/span&&span class=&n&&oldPassword&/span&&span class=&o&&.&/span&&span class=&na&&trim&/span&&span class=&o&&());&/span&
&span class=&k&&return&/span& &span class=&n&&oldPassword&/span&&span class=&o&&.&/span&&span class=&na&&Equals&/span&&span class=&o&&(&/span&&span class=&n&&GetStudent&/span&&span class=&o&&(&/span&&span class=&n&&id&/span&&span class=&o&&).&/span&&span class=&na&&LoginPassword&/span&&span class=&o&&);&/span&
&span class=&o&&}&/span&
&span class=&kd&&private&/span& &span class=&n&&Boolean&/span& &span class=&nf&&SaveNewPassword&/span&&span class=&o&&(){&/span&
&span class=&n&&newPassword&/span& &span class=&o&&=&/span& &span class=&n&&EncodeHelper&/span&&span class=&o&&.&/span&&span class=&na&&MD5&/span&&span class=&o&&(&/span&&span class=&n&&newPassword&/span&&span class=&o&&.&/span&&span class=&na&&trim&/span&&span class=&o&&());&/span&
&span class=&k&&return&/span& &span class=&k&&this&/span&&span class=&o&&.&/span&&span class=&na&&UpdateStudent&/span&&span class=&o&&((&/span&&span class=&k&&new&/span& &span class=&n&&Student&/span&&span class=&o&&(&/span&&span class=&n&&id&/span&&span class=&o&&,&/span& &span class=&n&&newPassword&/span&&span class=&o&&)));&/span&
&span class=&o&&}&/span&
&span class=&c1&&//其余部分略&/span&
&span class=&o&&}&/span&
&/code&&/pre&&/div&&br&&p&&b&通过提取类参、将公共变量改为类变量,使函数参数尽可能减少,越少越好。&/b&&/p&&br&&p&&b&&i&这样&/i&&/b&&b&&i&每&/i&&/b&&b&&i&重构一次函数,就修改相应的调用语句。然后&/i&&/b&&i&&b&Run -& Test,保证每次调用都结果不变。&/b&&/i&&/p&&br&&p&++++++++++++++++我是做总结的分割线++++++++++++++++&/p&&p&到这里已经谈了关于变量、代码块、以及函数的重构方法。所有的这些重构,说到底都是为了将函数写漂亮。那什么是漂亮的函数?我的目标是:&/p&&ol&&li&每个函数每次只做一件事&br&&/li&&li&将函数的处理流程和具体实现分开&br&&/li&&/ol&&p&
例如下面的代码,既描述了更改密码的处理流程,又描述了验证的具体实现。&/p&&p&
需要将处于不同的层级的两块代码分开。&/p&&div class=&highlight&&&pre&&code class=&language-java&&&span class=&kd&&public&/span& &span class=&n&&Boolean&/span& &span class=&nf&&ChangePassword&/span&&span class=&o&&(&/span&&span class=&kt&&int&/span& &span class=&n&&id&/span&&span class=&o&&,&/span& &span class=&n&&String&/span& &span class=&n&&oldPassword&/span&&span class=&o&&,&/span& &span class=&n&&String&/span& &span class=&n&&newPassword&/span&&span class=&o&&)&/span& &span class=&o&&{&/span&
&span class=&n&&oldPassword&/span& &span class=&o&&=&/span& &span class=&n&&EncodeHelper&/span&&span class=&o&&.&/span&&span class=&na&&MD5&/span&&span class=&o&&(&/span&&span class=&n&&oldPassword&/span&&span class=&o&&.&/span&&span class=&na&&trim&/span&&span class=&o&&());&/span&
&span class=&n&&newPassword&/span& &span class=&o&&=&/span& &span class=&n&&EncodeHelper&/span&&span class=&o&&.&/span&&span class=&na&&MD5&/span&&span class=&o&&(&/span&&span class=&n&&newPassword&/span&&span class=&o&&.&/span&&span class=&na&&trim&/span&&span class=&o&&());&/span&
&span class=&k&&if&/span& &span class=&o&&(!&/span&&span class=&n&&oldPassword&/span&&span class=&o&&.&/span&&span class=&na&&Equals&/span&&span class=&o&&(&/span&&span class=&k&&this&/span&&span class=&o&&.&/span&&span class=&na&&GetStudent&/span&&span class=&o&&(&/span&&span class=&n&&id&/span&&span class=&o&&).&/span&&span class=&na&&LoginPassword&/span&&span class=&o&&))&/span& &span class=&o&&{&/span&
&span class=&k&&return&/span& &span class=&kc&&false&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span&
&span class=&k&&return&/span& &span class=&k&&this&/span&&span class=&o&&.&/span&&span class=&na&&UpdateStudent&/span&&span class=&o&&(&/span&&span class=&k&&new&/span& &span class=&n&&Student&/span&&span class=&o&&(&/span&&span class=&n&&id&/span&&span class=&o&&,&/span& &span class=&n&&newPassword&/span&&span class=&o&&));&/span&
&span class=&o&&}&/span&
&/code&&/pre&&/div&
函数读起来应该像书的目录&br&&p&
我们读目录时,先看共有多少章节,再看一个章节里分了哪些小节,最后可根据索引去查询具体内容。&/p&&p&
于是我写的函数大体这样:&/p&&p&
1.最高层次的函数描述处理流程,流程中的每一步就是一个函数
-& 介绍章节&/p&&p&
2. 1中每一步描述处理方法,每一个方法就是一个函数
-& 章节里分小节&/p&&p&
3. 2中的每一个函数描述具体算法
-& 具体内容&/p&&p&
这样读代码时,可以先从【1流程】看起,不必纠结具体的处理方法;&/p&&p&
看懂后再了解【2方法】,不必拘泥于算法;&/p&&p&
逐层升入,以此类推...&/p&&br&&p&另外有一些个人的经验是:&/p&&p&1.不要有else;&/p&&p&2.将if、while、for里的代码块用函数代替;&/p&&p&3.尽量少的函数参数;&/p&&p&4.不要怕函数体短小(1~15行就行);&/p&&p&
※短小的函数读起来轻而易举,同时能将修改限定在最小范围&/p&&br&&p&&i&--------------------------------------&/i&&i&----&/i&&i&--&/i&更新于&i&--------------------------------------&/i&&i&----&/i&&i&--&/i&&br&&/p&&p&函数的重构讲完了,来谈谈如何重构类。&/p&&p&这个问题可以分解为:重组一个类和分解一个类。&/p&&p&&b&&u&6.重组一个类&/u&&/b&&/p&&p&类是怎样划分的?也许是基于你头脑中一个实体的映射,也许是基于UML的一个建模?&/p&&p&但既有的代码用起来,也有这样那样的不顺手。是时候祭出法宝,重新审视既有的函数和类了。&/p&&p&这个办法在重构第5法中提到过:尽可能减少函数的参数。&/p&&p&&b&规则1:&/b&&/p&&blockquote&&p&
当你发现函数的多数参数,是另一个类A的成员变量 &/p&&p&
-& 将该函数从现有类抽离出来,改造成为A的方法&/p&&/blockquote&&p&&b&规则2:&/b&&/p&&blockquote&&p&
当你发现若干函数有相同的参数,且无有关的类变量与之对应&/p&&p&
-& 重新定义一个类,将这些函数作为类方法,其相同的行参作为类的成员变量&/p&&/blockquote&&p&重构以后发现成员方法的参数减少,成员变量在方法体内被充分使用。&/p&&br&&p&&i&&b&然后Run -& Test,确保每次函数的变化(参数变更、类间移动)都不影响其output。&/b&&/i&&/p&&br&&p&&b&&u&7.分解一个类&/u&&/b&&/p&&p&在函数重构中,一直有个概念:函数一次只能做一事。&/p&&p&同样的,一个类如果责任过多,做了太多太多事,也不利于代码的维护。&/p&&p&&b&如果你发现类的某些成员变量,只被部分方法所使用,而另一些变量,被其他方法所使用,就意味这你可以分解这个类。&/b&&/p&&p&以一个例子来说明重构的方法:&/p&&div class=&highlight&&&pre&&code class=&language-java&&&span class=&kd&&public&/span& &span class=&kd&&class&/span& &span class=&nc&&Person&/span& &span class=&o&&{&/span&
&span class=&kd&&private&/span& &span class=&n&&String&/span& &span class=&n&&name&/span&&span class=&o&&;&/span&
&span class=&kd&&private&/span& &span class=&n&&String&/span& &span class=&n&&officeAreaCode&/span&&span class=&o&&;&/span&
&span class=&kd&&private&/span& &span class=&n&&String&/span& &span class=&n&&officeNumber&/span&&span class=&o&&;&/span&
&span class=&kd&&public&/span& &span class=&n&&String&/span& &span class=&nf&&getName&/span&&span class=&o&&()&/span& &span class=&o&&{&/span&
&span class=&k&&return&/span& &span class=&n&&name&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span&
&span class=&kd&&public&/span& &span class=&n&&String&/span& &span class=&nf&&getTelephoneNumber&/span&&span class=&o&&()&/span& &span class=&o&&{&/span&
&span class=&k&&return&/span& &span class=&s&&&(&&/span& &span class=&o&&+&/span& &span class=&n&&officeAreaCode&/span& &span class=&o&&+&/span& &span class=&s&&&)&&/span& &span class=&o&&+&/span& &span class=&n&&officeNumber&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span&
&span class=&kd&&public&/span& &span class=&n&&String&/span& &span class=&nf&&getOfficeAreaCode&/span&&span class=&o&&()&/span& &span class=&o&&{&/span&
&span class=&k&&return&/span& &span class=&n&&officeAreaCode&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span&
&span class=&kd&&public&/span& &span class=&kt&&void&/span& &span class=&nf&&setOfficeAreaCode&/span&&span class=&o&&(&/span&&span class=&n&&String&/span& &span class=&n&&officeAreaCode&/span&&span class=&o&&)&/span& &span class=&o&&{&/span&
&span class=&k&&this&/span&&span class=&o&&.&/span&&span class=&na&&officeAreaCode&/span& &span class=&o&&=&/span& &span class=&n&&officeAreaCode&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span&
&span class=&kd&&public&/span& &span class=&n&&String&/span& &span class=&nf&&getOfficeNumber&/span&&span class=&o&&()&/span& &span class=&o&&{&/span&
&span class=&k&&return&/span& &span class=&n&&officeNumber&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span&
&span class=&kd&&public&/span& &span class=&kt&&void&/span& &span class=&nf&&setOfficeNumber&/span&&span class=&o&&(&/span&&span class=&n&&String&/span& &span class=&n&&officeNumber&/span&&span class=&o&&)&/span& &span class=&o&&{&/span&
&span class=&k&&this&/span&&span class=&o&&.&/span&&span class=&na&&officeNumber&/span& &span class=&o&&=&/span& &span class=&n&&officeNumber&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span&
&span class=&o&&}&/span&
&/code&&/pre&&/div&&p&这段代码中,name只被getName()使用,其余的成员变量和方法看起来另成一派。于是我们将Person类&b&拆分为两个&/b&:&/p&&div class=&highlight&&&pre&&code class=&language-java&&&span class=&kd&&public&/span& &span class=&kd&&class&/span& &span class=&nc&&Person&/span& &span class=&o&&{&/span&
&span class=&kd&&private&/span& &span class=&n&&String&/span& &span class=&n&&name&/span&&span class=&o&&;&/span&
&span class=&kd&&public&/span& &span class=&n&&String&/span& &span class=&nf&&getName&/span&&span class=&o&&()&/span& &span class=&o&&{&/span&
&span class=&k&&return&/span& &span class=&n&&name&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span&
&span class=&o&&}&/span&
&span class=&kd&&public&/span& &span class=&kd&&class&/span& &span class=&nc&&TelephonePhone&/span& &span class=&o&&{&/span&
&span class=&kd&&private&/span& &span class=&n&&String&/span& &span class=&n&&officeAreaCode&/span&&span class=&o&&;&/span&
&span class=&kd&&private&/span& &span class=&n&&String&/span& &span class=&n&&officeNumber&/span&&span class=&o&&;&/span&
&span class=&kd&&public&/span& &span class=&n&&String&/span& &span class=&nf&&getTelephoneNumber&/span&&span class=&o&&()&/span& &span class=&o&&{&/span&
&span class=&k&&return&/span& &span class=&s&&&(&&/span& &span class=&o&&+&/span& &span class=&n&&officeAreaCode&/span& &span class=&o&&+&/span& &span class=&s&&&)&&/span& &span class=&o&&+&/span& &span class=&n&&officeNumber&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span&
&span class=&kd&&public&/span& &span class=&n&&String&/span& &span class=&nf&&getOfficeAreaCode&/span&&span class=&o&&()&/span& &span class=&o&&{&/span&
&span class=&k&&return&/span& &span class=&n&&officeAreaCode&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span&
&span class=&kd&&public&/span& &span class=&kt&&void&/span& &span class=&nf&&setOfficeAreaCode&/span&&span class=&o&&(&/span&&span class=&n&&String&/span& &span class=&n&&officeAreaCode&/span&&span class=&o&&)&/span& &span class=&o&&{&/span&
&span class=&k&&this&/span&&span class=&o&&.&/span&&span class=&na&&officeAreaCode&/span& &span class=&o&&=&/span& &span class=&n&&officeAreaCode&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span&
&span class=&kd&&public&/span& &span class=&n&&String&/span& &span class=&nf&&getOfficeNumber&/span&&span class=&o&&()&/span& &span class=&o&&{&/span&
&span class=&k&&return&/span& &span class=&n&&officeNumber&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span&
&span class=&kd&&public&/span& &span class=&kt&&void&/span& &span class=&nf&&setOfficeNumber&/span&&span class=&o&&(&/span&&span class=&n&&String&/span& &span class=&n&&officeNumber&/span&&span class=&o&&)&/span& &span class=&o&&{&/span&
&span class=&k&&this&/span&&span class=&o&&.&/span&&span class=&na&&officeNumber&/span& &span class=&o&&=&/span& &span class=&n&&officeNumber&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span&
&span class=&o&&}&/span&
&/code&&/pre&&/div&&p&这样划分后两个类,责任划分清晰明了。 但人总得有个电话号码吧,所以还得把两者的联系加上:&/p&&br&&div class=&highlight&&&pre&&code class=&language-java&&&span class=&kd&&public&/span& &span class=&kd&&class&/span& &span class=&nc&&Person&/span& &span class=&o&&{&/span&
&span class=&kd&&private&/span& &span class=&n&&String&/span& &span class=&n&&name&/span&&span class=&o&&;&/span&
&span class=&kd&&private&/span& &span class=&n&&TelephonePhone&/span& &span class=&n&&telephonePhone&/span& &span class=&o&&=&/span& &span class=&k&&new&/span& &span class=&n&&TelephonePhone&/span&&span class=&o&&();&/span&
&span class=&kd&&public&/span& &span class=&n&&String&/span& &span class=&nf&&getName&/span&&span class=&o&&()&/span& &span class=&o&&{&/span&
&span class=&k&&return&/span& &span class=&n&&name&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span&
&span class=&kd&&public&/span& &span class=&n&&String&/span& &span class=&nf&&getTelephoneNumber&/span&&span class=&o&&()&/span& &span class=&o&&{&/span&
&span class=&k&&return&/span& &span class=&n&&telephonePhone&/span&&span class=&o&&.&/span&&span class=&na&&getTelephoneNumber&/span&&span class=&o&&();&/span&
&span class=&o&&}&/span&
&span class=&o&&}&/span&
&/code&&/pre&&/div&&br&&br&在Person类中添加telephonePhone成员变量,&b&建立从旧类到新类的连接关系&/b&。&br&&br&&i&&b&每次搬移一个变量或方法时,Run -& Test。&/b&&/i&&br&&br&&br&&b&&u&8.消除类的重复&/u&&/b&&br&经过这么多的重构尝试,你应该注意到重复是编码的大忌。&br&函数中重复的代码块可变为函数,那么类中重复的变量和方法呢?Bingo,就是父类(或接口)!&br&&b&规则:&/b&&br&&blockquote&1.建立或修改父类,添加类中重复的变量和方法名;&br&2.将添加的变量或方法限定为protected或public;&br&3.之前的类继承该父类;&br&4.如果重复的方法处理逻辑一致,就在父类中实现该方法,视情况添加final限定;&br&5.如果重复的方法处理不一致,则父类中只声明方法名(或提取成接口)。视情况添加abstract限定;&br&6.移出子类中的重复变量和函数;&/blockquote&按照这种方式越重构下去,会发现父类越像是一个模版:把控了业务处理的流程,把具体的算法逻辑,交由子类重载。 -- 这便是设计模式中的[模版模式]。&br&&br&&b&&i&子类每移出一次重复变量和函数,Run -& Test,确保子类对父类相关字段或方法的正确使用。&/i&&/b&&br&&br&&br&个人对重构方法的理解大体就是如此了。&br&在这篇文章的最后,再一次和各位分享我对重构的认识:&br&&blockquote&&b&1.重构是个持续的过程&/b&&br&
并非等到程序无法控制的最后,才进行重构。恰恰相反,从你写第一个函数、第一个类开始,就想着重构它吧。越早开始重构,就会让项目开发越早进入良性循环,避免后续莫名奇妙的错误,以及大量耗时的修改。&br&&b&2.重构将更深入理解编程&/b&&br&
审视重构后的代码,会发现在不知不觉中,用到了抽象,用到了多态,用到了设计模式。这些编程中的概念,我们往往只知道是什么,却不知道它们从何而来、为何而去?重构的过程就像一次拾遗,让代码清晰的揭示:这些概念是因何产生,以及它们被使用的场景。&br&--人类最初数数时,只知道加法。后来它们总结出了乘法,应用在生活里简化了计算。一次次的重构,就是不断总结、孰能生巧的过程。我们回顾重构后的代码,给它分类,叫它XX模式。时间久了,编程遇到类似的需求时,就会自然而然想使用该模式。&/blockquote&&br&在过去的项目中,见识过糟糕的代码是如何带来灾难性的后果的:要不就是程序产生莫名奇妙的错误,要不就是一次小小的修改就牵一发动全身;&br&而另一方面,我们也曾体会过重构带来的美妙:一切都是简洁易修改的。往往我们面对一次大的逻辑变动,经调查后才发现,原来只需改一个函数,一切都会迎刃而解。&br&Wow,重构让一切的代码,都变得刚刚好!&br&&br&++++++++++++++++我是有彩蛋的分割线++++++++++++++++&br&前前前回书有说到,有if、else的地方就有可能使用多态。举一个例子,JAVA的对象在未创建时为NULL,对一个NULL对象操作会引发系统错误。因而在代码中常需要对一个对象是否为NULL进行判断,如:&br&&div class=&highlight&&&pre&&code class=&language-java&&&span class=&kd&&public&/span& &span class=&n&&Book&/span& &span class=&nf&&getBook&/span&&span class=&o&&(&/span&&span class=&kt&&int&/span& &span class=&n&&id&/span&&span class=&o&&)&/span& &span class=&o&&{&/span&
&span class=&k&&if&/span& &span class=&o&&(&/span&&span class=&n&&id&/span& &span class=&o&&&&/span& &span class=&mi&&0&/span&&span class=&o&&)&/span& &span class=&o&&{&/span&
&span class=&k&&return&/span& &span class=&kc&&null&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span&
&span class=&k&&return&/span& &span class=&k&&new&/span& &span class=&n&&Book&/span&&span class=&o&&(&/span&&span class=&mi&&1&/span&&span class=&o&&,&/span& &span class=&s&&&Design Pattern&&/span&&span class=&o&&,&/span& &span class=&mi&&100&/span&&span class=&o&&);&/span&
&span class=&o&&}&/span&
&/code&&/pre&&/div&&div class=&highlight&&&pre&&code class=&language-java&&&span class=&n&&Book&/span& &span class=&n&&book&/span& &span class=&o&&=&/span& &span class=&n&&getBook&/span&&span class=&o&&(-&/span&&span class=&mi&&1&/span&&span class=&o&&);&/span&
&span class=&k&&if&/span& &span class=&o&&(&/span&&span class=&n&&book&/span& &span class=&o&&!=&/span& &span class=&kc&&null&/span&&span class=&o&&)&/span& &span class=&o&&{&/span&
&span class=&n&&book&/span&&span class=&o&&.&/span&&span class=&na&&getName&/span&&span class=&o&&();&/span&
&span class=&o&&}&/span&
&/code&&/pre&&/div&&br&book != null 和 book == null成了两个分支。我们可以:&br&1.添加Book的一个NULL子类&br&2.在创建Book对象时,视情况创建NULL子类&br&3.在调用Book方法的逻辑处利用多态,去掉对象是否为null的判断&br&&br&重构后的代码变为:&br&&div class=&highlight&&&pre&&code class=&language-java&&&span class=&c1&&//添加的Null对象&/span&
&span class=&kd&&public&/span& &span class=&n&&Class&/span& &span class=&n&&NullBook&/span& &span class=&kd&&extends&/span& &span class=&n&&Book&/span& &span class=&o&&{&/span&
&span class=&kd&&public&/span& &span class=&nf&&NullBook&/span&&span class=&o&&()&/span& &span class=&o&&{&/span&
&span class=&o&&}&/span&
&span class=&nd&&@Override&/span&
&span class=&kd&&public&/span& &span class=&n&&String&/span& &span class=&nf&&getName&/span&&span class=&o&&()&/span& &span class=&o&&{&/span&
&span class=&k&&return&/span& &span class=&s&&&&&/span&&span class=&o&&;&/span&
&span class=&o&&}&/span&
&span class=&o&&}&/span&
&/code&&/pre&&/div&&div class=&highlight&&&pre&&code class=&language-text&&//创建Book对象
public Book getBook(int id) {
if (id & 0) {
return new NullBook();
return new Book(1, &Design Pattern&, 100);
&/code&&/pre&&/div&&div class=&highlight&&&pre&&code class=&language-java&&&span class=&c1&&//调用Book方法时去掉null判断&/span&
&span class=&n&&Book&/span& &span class=&n&&book&/span& &span class=&o&&=&/span& &span class=&n&&getBook&/span&&span class=&o&&(-&/span&&span class=&mi&&1&/span&&span class=&o&&);&/span&
&span class=&n&&book&/span&&span class=&o&&.&/span&&span class=&na&&getName&/span&&span class=&o&&();&/span&
&/code&&/pre&&/div&&br&&以上&
&--------- Modified at
start ---------& 以下是关于重构的个人书单。 两本就够了,别的都大同小异,有兴趣的朋友可以去读读:
&--------- Modified at
end ---------& &--------- Modified a…
&p&-&/p&&br&&p&《复仇者联盟2:奥创纪元》(以下简称《复联2》)是乔斯·韦登直接指导的最后一部漫威电影,也延续了他一贯以来的风格,注重叙事,风趣幽默,信息量大,留下大量空白供反复体味。虽然由于片长和市场原因,韦登不得不做了妥协,导致不少地方显得仓促,如删减了雷神在幻梦中看到了洛基等场景,但依然能看出韦登在其中强烈的表达欲望,正如他在采访中所说:「&b&这是一部很私人的电影。&/b&」&br&&/p&&br&&p&电影依旧延续了《复联1》的叙事模式。复仇者们接到神盾局通知(该段情节见《神盾局特工》S2E19)通知,前往索科维亚寻找洛基的权杖,胜利之后,钢铁侠托尼·史塔克为应对可能发生的危机,开启奥创计划,但奥创却想消灭整个人类,他联合快银和红女巫,通过心灵控制使复仇者四分五裂。但自然,经过最后的争斗,在幻视和倒戈的快银、红女巫帮助下,复仇者取得了最终的胜利。&/p&&br&&p&超级英雄作品是现代形态的古希腊神话,与《荷马史诗》、《埃涅阿斯纪》、《贝奥武甫》一样,是我们如今时代的神话与史诗。在现实当中,英雄已然退隐,普通民众管好自己的生活,并不需要英雄来干涉参与。但在宽广的银幕上,乔斯·韦登郑重摆好了一尊尊希腊雕像,通过光影来讲述英雄们的伟大冒险,但这一次,英雄们在神性之外,也更接近凡人。&/p&&br&&figure&&img src=&https://pic2.zhimg.com/50/82d2ef71eb7fb0fe852cc60_b.jpg& data-rawwidth=&600& data-rawheight=&249& class=&origin_image zh-lightbox-thumb& width=&600& data-original=&https://pic2.zhimg.com/50/82d2ef71eb7fb0fe852cc60_r.jpg&&&/figure&&br&&p&在《复联2》中,英雄们面临着前所未有的挑战,这并不仅仅因为奥创的强大,也因为他们需要直面内心的恐惧与忧虑。他们既要战胜前所未有的敌人,也要战胜自己的内心,在电影中,他们第一个任务自然成功了,但第二个任务却未能真的完成。&/p&&br&&p&电影里的外部威胁是奥创机器人。史塔克认为地球正面临前所未有的危机,于是他和布鲁斯·班纳联手制造了奥创机器人,并利用心灵之石赋予它思考的能力,希望它能够维护世界和平,但奥创却认为,对世界和平威胁最大的正是人类,于是它开始了人类灭绝计划,希望自己成为新世界的神。&/p&&br&&p&「在这块磐石上,我将建立我的教会。」&b&这磐石并不是振金(电影翻译为钒合金,此处按约定俗成来),而是恐惧。&/b&它说人们仰望天空的时候,能看得到希望,而它要把这希望和人类的生命一道夺走,于是它触发了索科维亚正中心教堂里的机关,整个城市升上天空,坠落时候的冲击力将灭绝几乎全部生命——当然这不是第一次发生,奥创认为这灭绝正是新生命进化的前奏曲。复仇者,既是和平的威胁,同时也是人类的希望,奥创自然要消灭他们。&/p&&br&&p&奥创在故事中期重挫复仇者,它的武器是「恐惧」。恐惧比利刃更伤人,在红女巫的蛊惑下,雷神去往英灵殿,看到了诸神黄昏;美国队长看到了自己再也回不去的过往,那支舞蹈也只是空许约;黑寡妇回到了红房子,看到了自己那黑暗的毕业典礼;班纳则直接变身发狂,在城市里四处作乱。以心理魔法引发人的恐惧回忆,是这部戏里红女巫的最主要功用,她混沌魔法的其他方面则未能细致展示,这显然也是韦登在故事上的特意处理。&/p&&br&&p&&b&《复联2&/b&&b&》本身也承担着双重任务&/b&,一方面它是漫威电影宇宙的关键一部,它是第二阶段的收官与扛鼎(虽然《蚁人》是第二阶段最后一部),同时也为第三阶段奠基;另一方面,他也是韦登的私人电影,韦登想要在这里好好讨论一些问题。商业大片与私人表达这二者之间,韦登找到了平衡点,那就是开掘英雄的内心世界,开掘他们的「恐惧本源」。展示英雄的内心,电影一方面得以展示英雄的「人性」——在平凡人看来,那些英雄「基本上都是神」——一方面借助幻梦预示未来将要发生的事情,同时,「恐惧」本身也是驱使人行动的重要心理动因,以此为基础韦登能够表达自己的想法,无论宗教还是政治。&/p&&br&&p&&b&当未知而巨大的威胁到来,每个人都会恐惧,因为无知,因为弱小。&/b&&/p&&br&&figure&&img src=&https://pic2.zhimg.com/50/f0611db5cbc29cb21b56491_b.jpg& data-rawwidth=&577& data-rawheight=&322& class=&origin_image zh-lightbox-thumb& width=&577& data-original=&https://pic2.zhimg.com/50/f0611db5cbc29cb21b56491_r.jpg&&&/figure&&br&&p&「在神明与怪物的时代里,人类价值几何?」《复仇者联盟》的删减片段中,希尔特工接受讯问,引用了弗瑞的这句话,这时镜头转到托尔,血正沿着锤子流下来。&/p&&br&&figure&&img src=&https://pic2.zhimg.com/50/5a256bd6a38_b.jpg& data-rawwidth=&577& data-rawheight=&322& class=&origin_image zh-lightbox-thumb& width=&577& data-original=&https://pic2.zhimg.com/50/5a256bd6a38_r.jpg&&&/figure&&br&&p&在MCU(漫威电影宇宙)中,托尔并不仅仅因为其战斗力而显得重要。当托尔出现在那个小镇上,不仅引发了一场大战,更颠覆了很多人的固有观念。雷神托尔,神话与传说中的人物,如今活生生行走在地球上,而其他的神灵也不仅仅只生活在口耳纸笔之间,并且,他们也并非善意地。于是简这个角色便至为重要,不仅因为她让托尔能够牵挂人类,有了保护地球的理由,更因为她让其他地球人能够在某种程度上相信托尔这个神,或者说外星人。但是,当传说真的成真,凡人将如何面对石碑上的铭文和岩洞里的壁画?&/p&&br&&p&史塔克的恐惧并非没有理由。&/p&&br&&p&先前的争端还可以说是地球内部矛盾,但托尔之后又紧接而来的纽约之战,却让这个世界的信念摇摇欲坠。史塔克无疑是人类之中最优秀的之一,起码他自认为如此,也自认为应当承担起与这优秀相当的责任。未来正在发生,但这未来太不可控,在史塔克看到的未来,他的战友躺在地上,坚不可摧之盾四分五裂,而更糟糕的是,自己还活着,看到了这一切。&/p&&br&&figure&&img src=&https://pic2.zhimg.com/50/fdf86b0be67f8e4b129a700f645dc1f4_b.jpg& data-rawwidth=&577& data-rawheight=&292& class=&origin_image zh-lightbox-thumb& width=&577& data-original=&https://pic2.zhimg.com/50/fdf86b0be67f8e4b129a700f645dc1f4_r.jpg&&&/figure&&br&&p&史塔克是未来之人,他不会等待着未来发生,甚至也不会去预测未来动向,对他而言,更便捷的做法是创造未来,创造一个自己心目中最为理想的未来。他不是神,但他相信依赖科技的力量人可以对付神怪。红女巫对美国队长说,史塔克会不惜一切代价把事情做对。他孜孜寻求一种终极解决方案,给这个世界穿上铁甲。纽约大战时他们头顶上方90米的军队必然不是终极威胁,当更大的威胁来临时,史塔克要确保自己和地球都做好了准备,他要通过战斗来结束一切战斗,以一劳永逸的方式解决世界可能面临的问题,为此史塔克甘愿承担巨大风险,在班纳的帮助下,奥创诞生了。&/p&&br&&figure&&img src=&https://pic4.zhimg.com/50/24a7ec11bdb_b.jpg& data-rawwidth=&577& data-rawheight=&241& class=&origin_image zh-lightbox-thumb& width=&577& data-original=&https://pic4.zhimg.com/50/24a7ec11bdb_r.jpg&&&/figure&&br&&p&班纳的恐惧则来源于自己,来源于他内心的那个怪物。他大概没有史塔克那种“make a better world and future”的雄心壮志,他心心念念想的是“prepare for the worst”,并且他坚信自己就是“the worst”。「与怪物战斗的人,应当小心自己不要成为怪物」,在复仇者里,绿巨人无疑最具悲剧感,他的遭遇其实代表了人类对异化的恐慌——僵尸、吸血鬼、狼人,都可算是人的异化状态。班纳的悲情不仅在于他因事故(或者说现代诅咒)成为「怪物」——这事故在古代是神魔诅咒,在现代则是病毒辐射——而且因为他成为「怪物」的直接驱动力量是内心的愤怒,这根植于人的天性。在第一部的结局,班纳成功地驯服「内心的野兽」而使绿巨人成为了拯救者。但这并不能让他心安,他知道自己的理性无法成为完全的安全保障,毕竟人是这个世界最不可测的因素。当「最坏的事情」发生时,必须有措施能够阻止,比如自己亲自参与设计的「反浩克重甲」。黑寡妇总是背负着过去的枷锁,她觉得自己不配拥有现在的自由,这与班纳的情感有了互通,他俩之间的火花也并非全无因由,毕竟,整个队伍里只有他们坚信自己是怪物。&br&&/p&&br&&figure&&img src=&https://pic4.zhimg.com/50/35bbcf057b2becadf9a42adf_b.jpg& data-rawwidth=&577& data-rawheight=&240& class=&origin_image zh-lightbox-thumb& width=&577& data-original=&https://pic4.zhimg.com/50/35bbcf057b2becadf9a42adf_r.jpg&&&/figure&&br&&p&班纳对浩克的感情很复杂,他知道浩克有拯救世界的能力,也知道浩克能带来巨大灾难。复杂的感情最终通向了他对自身的怀疑和恐惧,他无法接纳黑寡妇的感情,他先是封闭了自己的内心,之后放逐了自己。最后自我放逐的时候,是浩克的形态,但那表情和动作却是班纳,他不再试图用理性控制那头野兽以保护这个世界,他要远离这个世界以保护它,他觉得浩克参与这个世界会带来更大灾难,班纳也会带来灾难,甚至复仇者参与世界也未必都是好的结果,毕竟他认为「人是世界的最大隐患」。复仇者不会去处理地狱厨房的争端,纽约大战时的消防员虽然有了一尊雕像,但他们多数因为感染外星病毒而痛苦地死去了。&/p&&br&&p&神一样的复仇者本身也给凡人带来了恐惧与不安。在一个一闪而过的场景中,我们能够看到复仇者并不总是受欢迎。电影开场大战,九头蛇轰击索科维亚的平民,钢铁军团前往助战,但平民却敌视那些机器人,投掷石块,墙后面的涂鸦也表明复仇者成为新霸权主义的象征,那些人认为复仇者并没能让世界变好,反而将地球拖入更大的危机之中。何况,当神降临世间,高高在上,如何能确认他是善意的?托尔是外星人,还是第一部中大反派的哥哥——虽然这个弟弟是「领养的」;托尼·史塔克很长一段时间里是战争贩子,快银和红女巫家破人亡跟他有莫大关联;浩克,随时会发狂毁灭一个城市。甚至,史塔克虽然总是出于善的动机,但行事却往往真的是霸权逻辑,「奥创无法分清拯救世界和毁灭世界,他是从哪儿学的呢?」为了对抗奥创,史塔克再次体现未来之人的思维方式,他要以更先进的武器来消灭奥创,要创造幻视,为此不惜与美国队长战斗。&/p&&br&&figure&&img src=&https://pic3.zhimg.com/50/0d4dc14ca06b1bd49bdda_b.jpg& data-rawwidth=&577& data-rawheight=&238& class=&origin_image zh-lightbox-thumb& width=&577& data-original=&https://pic3.zhimg.com/50/0d4dc14ca06b1bd49bdda_r.jpg&&&/figure&&br&&p&美国队长与史塔克的冲突其实来源于他们对现实的信念不同。大厅里美国队长与钢铁侠爆发的大战可以看作内战的序曲——明年将上映的美国队长第三部已经定名为「内战」。美国队长,上帝的正义使者,最早的复仇者,却是一个过时之人,被时空牢牢地束缚在现在。他邀请奥马哈海滩老兵来参加聚会,试图融入这个时代,但却一直无法真的找到自己的家,无论是不是在布鲁克林。他也坚信最基础的准则,「我们是复仇者」,坚信过去的时代的伦理信条并以此为决策的最终标准,他作战为的是保护每一个人而不是去赢得或者终结战争。因为这观念,在重大问题上他常常与史塔克分歧。当弗瑞驾驶着空天母舰飞来时候,他兴奋地爆了粗口(“language, cap!”),对快银说「这才是神盾局应有的样子。」他75年前的女友卡特创办神盾局,很可能为了延续美队的精神,保护世人,而今他终于再次看到了卡特心目中的神盾局。&/p&&br&&p&美国队长的这种神性是复仇者精神的基础。奥创意图以恐惧和毁灭来使自己成为新世界的神,但在美国队长看来,虽然这个世界有种种缺陷,虽然自己大概不属于这个世界了,但人依然应当有希望。奥创说:「你们想要保护这个世界却不想让他改变。」但这改变要基于人的自由意志才行,无论是谁,洛基、奥创还是史塔克,都不能决定其他人的命运。美国队长也能理解其他人心灵深处,他知道快银和红女巫为何做出了这种选择,遭遇战争,人总会被迫做出很多选择,但这并不代表人的心灵是扭曲的。&/p&&br&&figure&&img src=&https://pic4.zhimg.com/50/37c6cbdca57a5bbebb15f2d_b.jpg& data-rawwidth=&577& data-rawheight=&267& class=&origin_image zh-lightbox-thumb& width=&577& data-original=&https://pic4.zhimg.com/50/37c6cbdca57a5bbebb15f2d_r.jpg&&&/figure&&br&&p&美队的神性与人性紧密贴合,让他更接近真正意义的希腊英雄。鹰眼则是真正的凡人。外媒曾经有过一次复仇者排名的评选,鹰眼高居第二。理由是鹰眼反应了复仇者的真正精神。他与红女巫的话正体现了复仇者精神,无论你是谁,无论能力强弱,哪怕你只能在一座飞起的城市上用弓箭对付人工智能,但只要你站出来战斗,就是一名复仇者。鹰眼和很多普通人一样,肉体凡胎,有一技之长,也有妻儿牵挂。&/p&&br&&p&&b&在神和怪物之间,凡人的价值正在于他们自己的奋斗。&/b&&/p&&br&&p&Take my love.&/p&&br&&p&Take my land.&/p&&br&&p&Take me where I cannot stand.&/p&&br&&p&I don't care, I'm still free.&/p&&br&&p&You can't take the sky from me.&/p&&br&&figure&&img src=&https://pic4.zhimg.com/50/dcafde14dae_b.jpg& data-rawwidth=&577& data-rawheight=&395& class=&origin_image zh-lightbox-thumb& width=&577& data-original=&https://pic4.zhimg.com/50/dcafde14dae_r.jpg&&&/figure&&br&&p&最终大战时候,奥创意图以天空降下的恐惧来毁灭世人和他们的希望。但天空不能剥夺,正如十多年前韦登的美剧《萤火虫》主题曲所说的那样。诚然,&b&超级英雄会给这个世界带来意想不到的灾难,他们也不能假装世界依然是以前那样。但他们的奋斗,能将灭世的陨石化为希望的流星,给人带来希望,这正是英雄的意义。&/b&&/p&&br&&p&刘慈欣也标举英雄主义,但是他认为一方面英雄的行为要摆脱纤弱的人性,有时候甚至与民主和人权相背离,另一方面,英雄能够为了某个崇高的目标和理想而献身,并且,英雄大多是没有个人欲望的。所谓的英雄,很多时候就好像几何中的点一样。&/p&&br&&p&韦登的新时代神话则是充满着人性。英雄成其所是不仅因为力量,也因为抉择,他们总能站在人性这一边。那些英雄并非高高在上的神,而是「最好的人」,同时因为他们卓绝的能力,也会将人性的弱点放大而带来灾难,但他们始终为了世界和理想奋斗,让这个世界能够有更多的小农场让人安居。&/p&&br&&p&当然,某种意义而言,奥创并没有输,经典复仇者算是解散了,最后美国队长没能喊出的“assemble”是召集新复仇者的,漫威至此开始了全新的阶段,地球的命运将与宇宙大战紧密相连,天空阴云将更加密布。&/p&&br&&p&&b&那正是我们需要英雄的时候,也是需要我们自己成为英雄的时候。&/b&&/p&&br&&p&&b&-&/b&&/p&
- 《复仇者联盟2:奥创纪元》(以下简称《复联2》)是乔斯·韦登直接指导的最后一部漫威电影,也延续了他一贯以来的风格,注重叙事,风趣幽默,信息量大,留下大量空白供反复体味。虽然由于片长和市场原因,韦登不得不做了妥协,导致不少地方显得仓促,如删…
电影里让我最有感触的不是众英雄,而是奥创。不是天生反骨,只是电影里埋的处处伏笔,都让我由衷感动与战栗,是的,这并不仅仅是一部漫威电影,也是一部非常个人化的,非常Whedon-y的电影,处处都夹带了导演Joss Whedon自己的私货。(导演最初剪辑版超过了3个小时!!!迫于压力,剪去了快银与猩红女巫还有黑寡妇的诸多情节。。。也直接导致了这部分的弱化。还好主干是非常饱满的)&br&不是漫威骨灰粉无从深入谈世界观。但另一方面又很庆幸,这让我有了更多空间去了解Joss Whedon,继而被这位导演所折服。以下纯属对Joss Whedon及其这部电影的个人笔记。如有观者,如有不适,见谅。(另外,翻译真的很屎很屎很屎,重要的事情说三遍,严重影响到了对电影内涵的理解,所以我一定会等到导演剪辑版出来,重看并修正)&br&&br&————以下是笔记——&br&&br&先说奥创。他被Stark一手带到这世界,拥有与Stark相同的初衷——寻求世界和平,或者说是一种终极的万物和谐状态。但在改革进化观念上,奥创与Stark完全相反。&br&Stark算是复仇者联盟里的技术扛把子,却不是一个好的领袖(精神领袖当然是美队),因为他毕生致力于解散复仇者联盟——期待世界真正大和谐那一天,英雄们都可以回家, 世界仿若罩上一层金钟罩,固若金汤(“a suit of armor around the world.”)&br&而奥创呢,认为“There’s only one path to peace, human extinction.”世界想要获得真正的大和谐,人类必先灭绝。有录音为证:“每当地球归于平静,上帝就会投一块石头掀起波澜。相信我,他马上就要投了。”奥创的言下之意就是,我来做先锋开路,把人类杀光光后,天启时代才会到来。(奥创在这段中提到了诺亚,但翻译太屎我没理解到上下文,只能以后再补记。)关于进化,奥创的观点也很有意思。大人们生出小一点的大人,也就是孩子,孩子就是来取代父母的。&br&正好最近开始看《伊西斯的面纱》,把奥创的许多观点与书中所阐述的自然哲学对应起来想了想,很有意思。&br&古希腊哲学家赫拉克利特提出“自然爱隐藏”这句话,其中有一层含义即是“使事物出现的东西,也趋向于使事物消失”。“弓的名字是生(bios),它的作用却是死。”&br&所以进化的迷思也在这里。&br&托妞与奥创,好像科技改革的一体两面啊。他们对未来的实际作用,很可能是殊途同归的。Buzzfeed形容托妞说得好啊,“the one who seems most likely to accidentally eradicate humanity with all of the best intentions at heart.”&br&极端的进化,很有可能是通过对自身载体的完全否定来完成的。当人不再像细菌那样单纯复制,而是强迫性地进行两性繁殖,将DNA打散又重组,就已注定启动了死亡的程序。&br&(这里是复述弗朗索瓦·雅各布的观点:“没有任何东西强迫细菌进行有性繁殖。一旦性是强迫性的,形成的每一个遗传程序就不再通过精确复制单个程序,而是通过把两个不同程序进行匹配。对于演化来说必不可少的另一个条件就是死亡。这里的死亡不是来自外部,比如某个事故,而是来自内部,作为一种预先规定的必然性经由遗传程序来自于卵。”)&br&生存,从某种意义来说,就是为了死亡,完成真正的进化。对于奥创来说,他只不过是顺应了这样从内到外的趋势。&br&&br&奥创很像是Joss Whedon对科技世界的迷思,又不完全是他的观点。因为后来在托妞的一意孤行下又诞生了与奥创属性相同但又观念不太一样的英雄——幻视。当妇联忐忑地问他,你站在哪一边?幻视说,我站在有生命的这一边。&br&&br&奥创与幻视在树林里的最后一段对话,更为完整地呈现了Joss Whedon的想法(再一次谴责屎一样的翻译。。导演剪辑版后会再更正):&br&&blockquote&-“人类很奇怪,他们认为秩序和混乱是对立的,试图控制无法被控制的东西,可他们的衰败也不失优雅,我想你忽视了这一点。”&br&-“他们在劫难逃。”&br&-“是的,但事物并非因为长久才美丽,身处他们之中是一种荣幸。”&br&-“你幼稚得不可救药。”&br&-“是吗,我昨天才来到这世界。”&/blockquote&回顾下&a href=&//link.zhihu.com/?target=http%3A//v.163.com/movie//Q/M8VUJ2NU2_M8VUJ445Q.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&乔斯?韦登卫斯理大学2013届毕业典礼演讲&/a&,就会明白,他很强调事物的两面性,辩证又统一的两面性呵。(有盆友说到“二律背反”,但我最近倒是觉得Joss的想法更接近老子说哦,“反者道之动”与人“袭明”通则,我是脑洞开得有点大)甚至我可以将整个妇联2都看作是这次演讲内容的扩充。&br&&blockquote&“你们所有人都会死的,实际上已经开始死亡了。”&br&“Your body wants to die。Your body's ambition:Mulch。”&br&“森林里分出了两条路,而你选择了人少的那一条。”“不管你尽力去做什么,你都会做相反的事情。你需要做的是,是去尊重这个事实,去理解它,去挖掘它,去倾听这个相反的声音。”&br&“平静来自于对你内心深处永远无法平静这一事实的接受。”&br&“你们将要改变这个世界,这并不是你们的选择,而是世界的属性。”&/blockquote&电影中的奥创与托妞都是某种程度上的loser,因为他们不曾接受自己的反面。托妞未曾意识,世界和平来自对世界将永远动荡的理解与接受,死心眼地想要一劳永逸。而奥创也未曾意识,他并不是世界外部之神,自己其实也同样身处这世界之中。(当奥创问猩红女巫,你怎么不走你会死的,猩红女巫挖出了奥创的机械内核,就已是嘲讽奥创自以为是的超脱,他根本也身处其中却并不自知!)&br&幻视则与他们不同,他更具睿智,看到了事物的两面,动荡的平静,自我与世界的关照,再读一遍,“事物并非因为长久才美丽,身处他们之中是一种荣幸。”&br&&b&Joss在演讲中也曾讲到,“你身体与心智的矛盾,心智与它自身的矛盾,这些矛盾,这些张力是我们所有的最棒的天赋。”&/b&&br&对照到奥创与幻视,想一想也很有趣。奥创虽有自我意志,但依然是机械的顺应身体欲望的,(“你的身体想要死亡”),但幻视却多了一个Mind Stone,有了心智的觉醒,更具生命力。&br&Joss说:“这个时代是混沌无序的,我所创作的一切,都是希望观众能看到人类是如何在这样的时代里挣扎着、斗争着,去过上体面的高尚的生活。这是很艰难的过程,我们经常失败,但我们从不放弃。对我而言,这就是我会一直坚持传达的最重要的信息。”——(此处出自时光网专访一文)&br&&b&所以,妇联与奥创的对抗,并非善与恶的对立,而是人对于未来并存的希望与绝望吧。(很多观众都在吐槽奥创作为反派太弱了,但我想Joss本身就不喜欢将正反分离,他更在意的是正反之间形成的矛盾与张力,这个张力是生命力的体现)&/b&&br&&br&最后来说鹰眼。为什么鹰眼在妇联2的戏份特别多?为什么导演要插一段鹰眼的家庭生活啊,害得人人都以为他要领便当而不是快银!&br&好吧,我以为,鹰眼是Joss Whedon的部分自我投射,以及对英雄故事最后的表态。&br&Joss如是说:“He’s normcore,”是啊,人人都看得出来,鹰眼是英雄中最平平无奇的那一个,甚至可以说,是个普通人,不具备成为神或魔的暗区。 “Hawkeye’s dark secret being that he doesn’t have a dark secret is among my favorite things we’ve ever done.”(导演真的很调皮。。。)&br&他与妇联中绝大多数英雄是有距离的。他没有奥创所憎恨的英雄特质,没有其他英雄们突兀鲜明彼此难融的个性,他没有雷神的神性,没有美队的光辉,也没有托妞的精英主义,他有的只是一个老婆和两个孩子。(JW原话是:“You realize he has distance from these guys because everything that Ultron hates about them, everything that’s wrong with them, everything that they can be pulled apart for — their distance from humanity, their grandeur, their elitism — he doesn’t have any of that. He has a wife and kids.”)&br&电影中,鹰眼将英雄们带到寒酸的农场,导演是别有用心的啊。看着极客托妞竟然对一台破旧拖拉机束手无策,这场景是有多魔幻啊多黑色幽默啊,呵呵。“This movie is all about bringing them back down to earth.”&br&无论我们如何再渴慕英雄,最终也只是个人,与鹰眼一样平凡的人。电影的最后,奥创与幻视消失于电光火石间,雷神又上天了,托妞黯然地要暂别一阵,绿巨人放逐自己大海漂流,只有鹰眼回到家,拥抱老婆和孩子。&br&导演Joss自己也说呢,拍妇联2的这几年让他错过了许多家庭时光,也有过太多压力与折中(看得出Edgar Wright退出蚁人执导对他的触动也是蛮大的。)是时候停下脚

我要回帖

更多关于 印度停止进口伊朗原油 的文章

 

随机推荐