小酌重構(gòu)系列[8]——提取接口
前言
世間唯一“不變”的是“變化”本身,這句話同樣適用于軟件設(shè)計和開發(fā)。
在軟件系統(tǒng)中,模塊(類、方法)應(yīng)該依賴于抽象,而不應(yīng)該依賴于實現(xiàn)。
當(dāng)需求發(fā)生“變化”時,如果模塊(類、方法)依賴于具體實現(xiàn),具體實現(xiàn)也需要修改;
如果模塊(類、方法)依賴于接口,則無需修改現(xiàn)有實現(xiàn),而是基于接口擴展新的實現(xiàn)。
面向?qū)崿F(xiàn)?面向接口?
接口可以被復(fù)用,但接口的實現(xiàn)卻不一定能被復(fù)用。
面向?qū)崿F(xiàn)編程,意味著軟件的模塊(類、方法)之間的耦合性非常高,每次遭遇“變化”,都會涉及到修改,并且可能是牽一發(fā)而動全身的。
每次修改,都需要對原有的代碼重新測試,也可能給舊的代碼引入新的錯誤。
面向接口編程,是為了應(yīng)對軟件設(shè)計和開發(fā)中的“變化”,它是一種“以不變應(yīng)萬變”的思維模式。
只要確保我們的抽象(接口)是不變的,無論需求怎么變化,我們總能通過擴展新的實現(xiàn)自如地應(yīng)對。
接口是穩(wěn)定的,關(guān)閉的,但接口的實現(xiàn)是可變的,開放的。
開閉原則
“依賴于抽象,而不是具體實現(xiàn)”,它同時也是開閉原則的一種體現(xiàn)。
開閉原則的定義:當(dāng)軟件需要變化時,盡量通過擴展軟件實體的行為來實現(xiàn)變化,而不是通過修改已有的代碼來實現(xiàn)變化。它是面向?qū)ο蟮幕驹瓌t之一。
開閉原則主要有兩個特征:
(1)擴展開放(Open for extension)
(2)修改關(guān)閉(Closed for modification)
開閉原則要求模塊(類、方法)應(yīng)具備良好的擴展性,同時對現(xiàn)有的功能具有一定的保護能力。
開閉原則是一個比較模糊的一個原則,它沒有告訴你如何才能對擴展開放,以及如何才能對修改關(guān)閉。
這需要借助我們自身的經(jīng)驗,以及對需求的理解程度,去分析軟件系統(tǒng)中抽象的部分,識別其中的“變化”和“不變”。
提取接口
“提取接口”是面向?qū)ο缶幊坛S玫慕怦畈呗裕瑢⒁恍┛赡馨l(fā)生變化的具體實現(xiàn)提取為接口,將“變化”封裝起來,從而達到依賴接口、而非具體實現(xiàn)的目的。
示例
重構(gòu)前
以下是一個課程注冊的場景,這段代碼提供了2個類:ClassRegistration和RegistrationProcessor,RegistrationProcessor依賴于ClassRegistration的Create()方法和Total屬性。
public class ClassRegistration
{
public void Create()
{
// create registration code
}
public decimal Total { get; private set; }
}
public class RegistrationProcessor
{
public decimal ProcessRegistration(ClassRegistration registration)
{
registration.Create();
return registration.Total;
}
}
假如系統(tǒng)的業(yè)務(wù)發(fā)生了變化,ClassRegistration類的Create()方法已經(jīng)不能滿足新的業(yè)務(wù)了,我們需要使用另外的注冊方法。
這意味著,我們需要修改ClassRegistration類的Create()方法,且需要讓其同時滿足舊業(yè)務(wù)和新業(yè)務(wù)。
RegistrationProcessor依賴于ClassRegistration,既然ClassRegistration存在著諸多變數(shù),我們可以使用“提取接口”的重構(gòu)策略,讓RegistrationProcessor依賴于某個接口。
重構(gòu)后
重構(gòu)后,RegistrationProcessor依賴于IClassRegistration接口,RegistrationProcessor不必去關(guān)心IClassRegistration的具體實現(xiàn)是什么。
新的業(yè)務(wù)要求不同的Create()方式時,我們無需更改現(xiàn)有的ClassRegistration,而是添加新class并實現(xiàn)IClassRegistration接口。
另外,在不同場景下,舊業(yè)務(wù)和新業(yè)務(wù)的實現(xiàn)可能在不同場景下被使用。
這時,我們可以借助IoC框架將IClassRegistration接口的實例注入到指定場景。
public interface IClassRegistration
{
void Create();
decimal Total { get; }
}
public class ClassRegistration : IClassRegistration
{
public void Create()
{
// create registration code
}
public decimal Total { get; private set; }
}
public class RegistrationProcessor
{
public decimal ProcessRegistration(IClassRegistration registration)
{
registration.Create();
return registration.Total;
}
}
最后,下面這幅圖描述了這次重構(gòu)過程。
本文鏈接: 文章作者:keepfool 文章出處:http://www.rzrgm.cn/keepfool/ 如果您覺得閱讀本文對您有幫助,請點一右下角的“推薦”按鈕,您的“推薦”將是我最大的寫作動力!歡迎看官們轉(zhuǎn)載,轉(zhuǎn)載之后請給出作者和原文連接。

世間唯一“不變”的是“變化”本身,這句話同樣適用于軟件設(shè)計和開發(fā)。
在軟件系統(tǒng)中,模塊(類、方法)應(yīng)該依賴于抽象,而不應(yīng)該依賴于實現(xiàn)。
當(dāng)需求發(fā)生“變化”時,如果模塊(類、方法)依賴于具體實現(xiàn),具體實現(xiàn)也需要修改;
如果模塊(類、方法)依賴于接口,則無需修改現(xiàn)有實現(xiàn),而是基于接口擴展新的實現(xiàn)。本篇首先介紹了面向接口以及開閉原則的概念,然后提到了“提取接口”這個重構(gòu)策略,并用一個示例展示了這個重構(gòu)策略。

浙公網(wǎng)安備 33010602011771號