有关于Refactor(重构)与Source(源)的比较

上周发的blog上,谈及Vs.net与Eclipse的比较,在“快速由字段生成属性”的问题与兄弟们发生了争执,有兄弟认为在Vs.net2005重构中“Encapsulate Field...”,可以做到这一功能。我觉得这是一个概念上的错误,因为“封装字段“这个重构方法的本质并不是干这事。

算了,我干脆就谈谈“重构”吧

让我从头说起吧,当然俺的知识有限,肯定有说错的地方。
如果说错了,还请各位海涵。最重要的是指出俺的错误,不让俺一直错下去。

说到了“重构(refactor)”,也不得不说说源(Source),看看他们的比较。

一、Source
Source并不是一个标准的概念,目前来说只出现在Eclipse 中,他可以说是一堆方便写代码的功能的集合,来看看Eclipse中的Source菜单


(菜单内容就不仔细解释了,看英文就懂了)
Source的功能大多数是为了方便写代码之用,即他是在生成代码,也就是说,他的作用发生在“编写代码时”,他是“生成代码结构,而非改变代码结构
Source的功能很多,在实际操作中,可大大加快写代码的速度,大家可以自行看菜单项理解(强烈建议自己动手一试),我这里仅仅谈谈,上次发生争论的“Generate Getters and Setters..”的功能。
这里我图例一次,操作,希望大家不要闲烦。

这个“Generate Getters and Setters..”就是我上次说的,“快速生成属性..”。
我随便写一个类, 写了三个字段,让他帮我同时生成这三个属性:


/**
 * @author duliang
 * @version 1.0
 * <p> </p>
 */
public class TestField
{
 private String name = "";
 private String address = "";
 private boolean isNew = false;
 
}
操作如下:


OK,一切搞定,连注释都有了,自动生成如下代码:

/**
 * @author duliang
 * @version 1.0
 * <p> </p>
 */
public class TestField
{
 private String name = "";
 private String address = "";
 private boolean isNew = false;
 
 
 /**
  * @return Returns the address.
  */
 public String getAddress()
 {
  return (address);
 }
 /**
  * @param address The address to set.
  */
 public void setAddress(String address)
 {
  this.address = address;
 }
 /**
  * @return Returns the isNew.
  */
 public boolean isNew()
 {
  return (isNew);
 }
 /**
  * @param isNew The isNew to set.
  */
 public void setNew(boolean isNew)
 {
  this.isNew = isNew;
 }
 /**
  * @return Returns the name.
  */
 public String getName()
 {
  return (name);
 }
 /**
  * @param name The name to set.
  */
 public void setName(String name)
 {
  this.name = name;
 }

}


实际上我要说的就是这么一个简单的功能。
我图例的原因,就是告诉大家,这些操作发生在“代码编写时”。哈哈,很罗嗦吧:)

二 Refactor

OK,再来说说重构,这也是主题。

重构是指:在不改变代码功能的基础上,改变代码的结构
举几个重构的简单例子:
1. 重命名某个类,某个字段或者是本地变量,你则需要“rename“操作。
2. 某函数代码太长,你就需要将一个函数分成多个小函数,则你需要“Extract Method(抽取方法)”
3. 你的类,需要增加基类(接口),以更好的符合里氏代换、依赖转置原则,则你需要 “Extract Interface”
4. 某个方法要移至基类或子类,你则需要使用“Pull UP” 或 “Pull Down”
5.  。。。。。

重构是一种思想,当然你可以用手动改代码直接实现,但是你面对大项目时,你就会发现手动重构是多么痛苦,比如你在项目中,修改一个被其它人广泛使用的类名(方法名),如果你手动修改,必须得一个个的手动查找、修改,你认为不痛苦吗?

如果只需要点几下鼠标,就能搞定这一切,那多爽?
这就是开发工具提供重构的意义。

下面来看看Eclipse中提供的重构功能:

Vs.net 2005提供的有:



显然,Eclipse提供的要多得多。
当然就算是eclipse,提供的重构功能也并不是全部,慢慢加强吧。

OK,现在我们都知道“重构”是什么了,我们再来看看有兄弟指出的“Encapsulate Field...”方法到底是干什么。

从上两图中可以看出,这功能在Eclipse与Vs2005中都提供,可以说这方法是比较重要,比较常见的。

当然,首先我得承认,使用“Encapsulate Field...”确实能使用单个字段生成属性  ,似乎是实现了我们上次争论的功能。但是它既然称为重构的一种方法,则他的本质作用便不是这个,。

重构是干什么?他是要改变代码的结构,以让代码更便阅读,代码结构更合理。

因此“Encapsulate Field...”的作用是“封装字段的可见性”,发生成“代码编写后

初级程序员,经常干这种事情,就是为了访问方便,把一些字段设成public 或者说是protected、internal这些可能被外部直接修改的类型,拥有这种修饰符字段的类,是不安全的,因为有些字段我们经常是不允许外部更改的。
类设计的基本原则就是尽量减少提供修改类内部结构的方法。这样随意让别人就有权力更改内部字段,显然是不合理的。

因此这个时候就需要使用“Encapsulate Field...”这个重构方法,将代码重构,使这些字段通过get,set来访问,以控制字段的可见性,保证类的安全。

“Generate Getters and Setters..”与“Encapsulate Field...”还有个很大的区别,也可以说是Source与Refactor的区别:
“Generate Getters and Setters..”只是会改变当前的类的代码,而“Encapsulate Field...”则应改变与之相关的其它类的代码。

举个简单的例子,有A,B,C三个类,其它A类中有一个public字段field,B实现了 对这个字段的引用,C则设置这个字段。

重构前的代码:
public class A
{
 public String field = "HI, I am feidao";
}

public class B
{
 public B()
 {
  A a = new A();
  String str = a.field;
 }
}

public class C
{
 public C()
 {
  A a = new A();
  a.field = "";
 }
}

对A类的field字段进行“Encapsulate Field...”重构,重构后增加了get,set方法(在.Net中就是属性),且字段的public修饰符,改为private。重构后代码为:
public class A
{
 private String field = "HI, I am feidao";

 /**
  * @param field The field to set.
  */
 public void setField(String field)
 {
  this.field = field;
 }

 /**
  * @return Returns the field.
  */
 public String getField()
 {
  return field;
 }
}

重构后,B类的引用代码,则需要改为getField(),才能保证原有功能,当然这一切,开发工具,帮你自动帮你做了。
public class B
{
 public B()
 {
  A a = new A();
  String str = a.getField();
 }
}

同理C类,改为setField(),以改变此字段的值:
public class C
{
 public C()
 {
  A a = new A();
  a.setField("");
 }
}

大家注意红色字体,相信很直观的了了解“Encapsulate Field...”真正作用。

重构是非常有用的东西(其实Source也是),相信2005出来后,会增加.Net兄弟们对重构的认识。

重构的内容很多,理解运用好重构,可以让大家写出一手漂亮的代码。
有一本经典好书,就叫《重构》,英文原版忘记叫什么名字了,中文版是由候大师翻译的,里面的内容都是Java写的,但是 Java与C#语法差别不大,.Net的兄弟们不会存在看不懂的问题,当然极度反感Java的兄弟除外。
VB我就不太会,用VB.Net的兄弟们就不要挑我的刺了。

btw,运用,学好重构,首先还是得以设计模式为基础,否则你都不知道重构的目标。

Source与重构: 前者是生成代码结构,后者是改变代码结构;一个方便快速写代码,另一个使代码更加强壮,闻不到“坏味道”。


posted on 2004-06-19 02:32  飞刀  阅读(6232)  评论(10编辑  收藏  举报

导航