请先阅读上一篇文章
重构
即使最有思想性且最熟练的程序员也不能预见一个软件项目中的任何细微之处。问题总是出乎意外的出现,需求也可能在变化,结果是代码被优化,共享然后代替。
重构是一个惯用的方法:检查你所有的代码,找出其中能统一化和简单化的共同或者类似之处,使得你的代码更加容易维护和扩展。重构也包括探索一个设计模式是否能够应用到这个具体的问题上——这也能使解决方案简单化。
重构,简单点说是重命名一个属性或者方法,复杂点说是压缩一个已有的类。改变你的代码使得它符合一个或者更多的设计模式是另外一种重构——读完这本书后,你可能会去实现的。
没有什么能比例子来更好的解释重构了!
让我们考虑两个简单的类:CartLine和Cart。CartLine记录了购物车里面每个项目的单件价格和数量。比如CartLine可能记录着“四见红色的polo衬衣,每件19.99$”。Cart 是一个容器,用来装载一个或者更多的CartLine对象并执行一些相关的计算工作,比如购物车里面的所有商品的总花费。
下面是CartLine和Cart的简单实现:
// PHP5
class CartLine {
public $price = 0;
public $qty = 0;
}
class Cart {
protected $lines = array();
public function addLine($line) {
$this->lines[] = $line;
}
public function calcTotal() {
$total = 0;
// add totals for each line
foreach($this->lines as $line) {
$total += $line->price * $line->qty;
}
// add sales tax
$total *= 1.07;
return $total;
}
}
重构的第一步必须有足够的测试来覆盖你所有的代码。这样才能保证你修改的代码不能产生和你原来代码不同的结果。顺便提一下,除非你改变了需求(你代码期望的结果)或者在测试实例中发现了错误,你的测试代码是是不能改变的。
下面是一个测试CartLine和Cart的例子,它在重构的过程中是不会改变的。
function TestCart() {
$line1 = new CartLine;
$line1->price = 12; $line1->qty = 2;
$line2 = new CartLine;
$line2->price = 7.5; $line2->qty = 3;
$line3 = new CartLine;
$line3->price = 8.25; $line3->qty = 1;
$cart = new Cart;
$cart->addLine($line1);
$cart->addLine($line2);
$cart->addLine($line3);
$this->assertEqual(
(12*2 + 7.5*3 + 8.25) * 1.07,
$cart->calcTotal());
}
看着上面的代码,你可能会发现它们有一些“code smells”(代码臭味)——有着古怪的样子而且看起来好像是有问题的代码——它们就像重构的候选项。(更多关于code smells的资料请看http://c2.com/cgi/wiki?codesmell)。两个最直接的重构候选者是注释和计算(与销售税等相关的计算)。重构的一种形式:析取函数(Extract Method)将把这些难看的代码从cart::calcTotal()中提取出来,然后用一个合适的方法来替代它,从而使得代码更加简洁。
比如,你可以增加两个计算方法:lineTotal()和calcSalesTax():
protected function lineTotal($line) {
return $line->price * $line->qty;
}
protected function calcSalesTax($amount) {
return $amount * 0.07;
}
现在你可以重写calcTotal()函数:
public function calcTotal() {
$total = 0;
foreach($this->lines as $line) {
$total += $this->lineTotal($line);
}
$total += $this->calcSalesTax($total);
return $total;
}
到目前为止的改动都是有意义的(至少在这个例子的上下文中),它对于再次暂停和运行这些代码来验证结果依然正确是很有帮助的。记得,一个绿色的成功条的显示出来了!(译者注:本章开始时,作者提及到:绿色的条意味着测试都通过了。)
然而,目前的代码依然有一些可以挑剔的地方。其中一个就是在新方法lineTotal()中存取公共属性。很明显计算每行的之和的责任不应该属于Cart类,而应该在类CartLine里面实现。
再次重构,在CartLine中增加一个新的方法total()用来计算订单里面的每个项目的长期价钱。
public function total() {
return $this->price * $this->qty;
}
然后从类Cart中移除方法lineTotal(),并改变calcTotal()方法来使用新的cartLine::Total()方法。重新运行这个测试,你依然会发现结果是绿色条。
全新重构后的代码就是这样:
class CartLine {
public $price = 0;
public $qty = 0;
public function total() {
return $this->price * $this->qty;
}
}
class Cart {
protected $lines = array();
public function addLine($line) {
$this->lines[] = $line;
}
public function calcTotal() {
$total = 0;
foreach($this->lines as $line) {
$total += $line->total();
}
$total += $this->calcSalesTax($total);
return $total;
}
protected function calcSalesTax($amount) {
return $amount * 0.07;
}
}
现在这代码不再需要每行注释了,因为代码本身更好的说明了每行的功能。这些新的方法,更好的封装了计算这个功能,也更加容易适应将来的变化。(比如说,考虑不同大的销售税率)。另外,这些类也更加平衡,更容易维护。
这个例子显然是微不足道的,但是希望你能从中推断并预想出如何重构你自己的代码。
在编码的时候,你应该有出于两种模式中的一种:增加新的特征或者重构代码。当在增加特征的时候,你要写测试和增加代码。在重构的时候,你要改变你原有的代码,并确保所有相关的测试依然能正确运行。
关于重构的主要参考资料有Martin Fowler著作的《重构:改进原有代码的设计》(Refactoring:Improving the Design of Existing Code)。用一些精简点来总结Fowler的书,重构的步骤如下所示:
定义需要重构的代码
有覆盖所有代码的测试
小步骤的工作
每步之后都运行你的测试。编码和测试都是相当重复的——和编译型语言相比,解释型语言,比如PHP是容易很多的。
使用重构来使你的代码有更好的可读性和可修改性。
波比源码 » php教程:php设计模式之编程惯用法
levaquin 250mg pill purchase levaquin pill
dutasteride online zofran 4mg price ondansetron 8mg generic
order aldactone 100mg sale order valacyclovir 500mg pill generic fluconazole
purchase ampicillin for sale purchase bactrim without prescription erythromycin 250mg tablet
order fildena 100mg pills sildenafil 100mg without prescription buy robaxin 500mg online cheap
buy lamictal 200mg online cheap order mebendazole for sale buy generic retin gel
buy generic tadalis 10mg tadalafil medication buy voltaren pill
isotretinoin 20mg for sale amoxil 1000mg tablet buy zithromax
indocin sale buy generic amoxicillin order trimox online
tadalafil 20mg us Viagra next day delivery cost sildenafil 100mg
vrai cialis 20mg prix viagra 100mg generique en pharmacie viagra prix
prednisone tablet buy generic deltasone buy sildenafil 50mg sale
isotretinoin 20mg brand cost zithromax stromectol ebay
order doxycycline online clomid 50mg drug lasix medication
order clonidine online buy meclizine pill oral spiriva 9 mcg
buspar 10mg generic order dilantin online cheap oxybutynin 5mg pills
order alendronate 35mg sale paracetamol 500 mg for sale pepcid 40mg drug
isosorbide 20mg without prescription order micardis 80mg generic telmisartan 80mg usa
molnunat cost order generic molnunat 200mg order lansoprazole pills
zoloft cheap zoloft 100mg usa sildenafil order online
salbutamol 100 mcg canada cheap protonix 20mg sildenafil without prescription
order cialis 40mg for sale purchase prozac generic buy sildenafil sale
dapsone order online buy perindopril online cheap buy generic perindopril 8mg
order modafinil 200mg sale canadian pharmacy online best ivermectin 3 mg otc
luvox 50mg over the counter nizoral cheap glipizide 5mg drug
cheap isotretinoin 40mg buy generic amoxicillin 1000mg prednisone 10mg ca
purchase azithromycin generic zithromax 500mg price gabapentin 100mg brand
cialis 20 generic cialis india order generic viagra 100mg
lasix tablet doxycycline 200mg pill purchase hydroxychloroquine online cheap
olanzapine 10mg cost zyprexa us diovan generic
norvasc 5mg canada buy sildenafil 50mg online tadalafil 40mg oral
order clozaril 100mg for sale ipratropium 100mcg pills decadron 0,0,5 mg usa
viagra 50mg cheap order generic lisinopril 10mg lisinopril ca
order prilosec 10mg generic slot machine real online blackjack
zyvox order online zyvox 600mg ca gambling games
pay for assignments essay edit roulette wheel online
order cialis online cheap sildenafil 20mg order generic sildenafil 100mg
triamcinolone medication desloratadine 5mg usa buy clarinex 5mg
purchase dapoxetine online buy synthroid generic order synthroid for sale
orlistat 120mg tablet buy diltiazem 180mg for sale zovirax 800mg brand
cialis overnight shipping usa buy clopidogrel for sale clopidogrel us
order baclofen 25mg generic baclofen 25mg oral ketorolac over the counter
sumatriptan tablet purchase dutasteride without prescription purchase dutasteride pill
tamsulosin medication order zofran generic buy spironolactone 25mg online
tadalafil uk order tadalafil 5mg online ciprofloxacin canada
buy zocor 10mg online cheap order finasteride 1mg online cheap purchase proscar
order flagyl generic trimethoprim for sale oral bactrim 480mg
purchase fluconazole online cheap diflucan 100mg tablet sildenafil fast shipping
buy keflex 500mg pills order erythromycin 500mg cost erythromycin
cialis overnight shipping order generic sildenafil 50mg viagra fast shipping
buy ceftin 500mg generic buy cefuroxime 500mg pills methocarbamol over the counter
hollywood casino online real money online casino real money no deposit cialis walmart
buy a term paper online buy stromectol 6mg ivermectin 3mg for people
free blackjack provigil 100mg cheap buy modafinil
lasix usa order furosemide without prescription order hydroxychloroquine 400mg online cheap
prednisone 10mg ca buy vermox 100mg generic mebendazole 100mg without prescription
buy tadacip generic order indomethacin buy generic indocin 50mg
order terbinafine online cheap suprax drug order amoxicillin 500mg
albuterol pills buy proventil 100 mcg pills cipro 500mg over the counter
purchase tadalafil mens ed pills order tadalafil 5mg online cheap
adalat buy online order adalat 10mg pills fexofenadine 120mg cheap
oral doxycycline 200mg buy doxycycline pills buy cleocin 300mg sale
buy diamox online imdur 40mg canada imuran brand
buy temovate cream oral clobetasol purchase cordarone pill
order amoxil 500mg for sale stromectol online buy india ivermectin
purchase fosamax pill buy ibuprofen 600mg generic cheap motrin 600mg
I really love to read such an excellent article. Helpful article. Hello Administ . Metropol Halı Karaca Halı Öztekin ve Selçuklu Halı Cami Halısı ve Cami Halıları Türkiye’nin En Büyük Cami Halısı Fabrikasıyız…
order fenofibrate 160mg cost viagra 50mg viagra mail order us
tadalafil cost purchase trimox for sale buy amoxicillin 250mg generic
order tadalafil 20mg without prescription buy sildenafil 50mg without prescription viagra 50mg pill
buy minocin generic generic terazosin buy terazosin 5mg generic
order modafinil online buy provigil 100mg sale order phenergan generic
buy sildenafil 100mg pill order sildenafil 50mg online order proscar sale
buy isotretinoin accutane 20mg over the counter ampicillin 250mg price
ivermectin pills for humans over the counter ed pills that work prednisone 40mg usa
ventolin inhalator cheap purchase albuterol augmentin 625mg pills
isotretinoin 40mg brand order isotretinoin 40mg pills order zithromax for sale
purchase prednisolone lasix 100mg pill buy furosemide for sale diuretic
azathioprine canada imuran uk order naprosyn 250mg pill
order ditropan 5mg online cheap ditropan 2.5mg for sale order oxcarbazepine 600mg pills
order avlosulfon 100mg pills order asacol pill tenormin tablet
zocor 10mg sale buy simvastatin without prescription sildenafil without a doctor’s prescription
brand sildenafil 100mg viagra 25mg for sale purchase cialis sale
uroxatral 10 mg tablet uroxatral online buy diltiazem 180mg pill
phenergan without prescription purchase promethazine sale order cialis 5mg pill
where can i buy coumadin purchase coumadin sale order allopurinol 300mg sale