簡單就是美——單一職責原則(轉)
所謂單一職責原則,就是就一個類而言,應該僅有一個引起它的變化的原因。換句話說,一個類的功能要單一,只做與它相關的事情。
這個原則是最簡單、最容易理解,卻是最不容易做到的事情。這個原則的道理誰都理解,可是在實踐中呢?
我們來看一個例子:
if(action.equals("load")&&tab.equals("1")){
request.setAttribute("tabId",tab);
form.set("tabId",tab);
speciManager.loadIncrement(actionForm, request, tab);
}
if(action.equals("Save")&&tab.equals("1")){
System.out.println("inter increment save action");
……
request.setAttribute("tabId",tab);
}
if(action.equals("load")&&tab.equals("2")){
request.setAttribute("tabId",tab);
form.set("tabId",tab);
speciManager.loadMeasureMent(actionForm, request, tab);
}
if(action.equals("Save")&&tab.equals("2")){
……
System.out.println("inter increment save action");
speciManager.loadIncrement(actionForm, request, tab);
form.set("tabId",tab);
request.setAttribute("tabId",tab);
}
一看就知道這個類做了太多的工作,它既要load一個tab爲1的頁面和一個tab爲2的頁面;又要save一個tab爲1頁面和一個tab爲2的頁面。這個類的代碼我只截取了裏面很少的一部分,絕大部分的代碼我都省略掉了。這段代碼寫到最後是越來越混亂,直到最後失敗。
對照着這個例子,我們再來分析一下爲什麼要遵守單一職責願則:
第一、有助於我們分析和編碼的思路的清晰。當你的代碼裏有了三層或以上的if語句或for語句的嵌套的時候,你不要跟我說,你已經把問題分析得很清楚了。多層嵌套的if或for語句只能說明你還沒有把問題分析清楚。
第二、使我們的編碼、測試和維護變得簡單。
第三、將一個個複雜的問題簡單化以後,易於代碼的重用。當你的代碼的多個功能攪和在一起的時候,你是沒辦法考慮代碼的重用的,因爲你的每一處代碼都有不同。
第四、易於系統的擴展。
好了,在這裏一二三四的列舉單一職責的原則不管用,我們需要看看實際的效果纔好。現在我們就來看看模式是怎麼來遵守這一原則的:
首先,我們來看簡單工廠模式。工廠類只有一個功能,就是產生一個個的對象產品。就這麼一個簡單的功能,但如果我們不把它拿出來,在客戶端就會出現這樣的代碼:
if(type.equals(“apple”))
{
Apple apple = new Apple();
……
}
else if(type.equals(“orange”))
{
Orange orange = new Orange();
……
}
else if(type.equals(“Banana”))
{
Banana banana = new Banana();
……
}
有了工廠,我們的客戶端就變成這樣:
Fruit fruit = Factory.getInstance(type);
……
我們的客戶端調用起來多麼的簡單,而且系統擴展起來也與客戶端無關。
我們再來看模板方法模式。
public abstract class Template {
public void totalAction()
{
commonAction();
differentAction();
}
private void commonAction()
{
//......
}
public abstract void differentAction();
}
這是一個模板類,它只做了一件事,就是所有子類的共同行爲;然後去由它的子類單獨完成自己的不同的行爲。
這樣的蓄意讓類的職責單一,擁有的好處是:第一、所有的子類的共同行爲,只在模板類裏構造一次,實現了代碼的重用。第二、將各子類不同的行爲分配到各子類裏去,使得子類極爲簡單,易於實現。
命令模式和策略模式的原理都相同,命令模式是對行爲的封裝,而策略模式是對算法的封裝。兩者都是要把相同的關注點和對他們的調用分離開,如命令模式是將行爲和對它們的調用分離開,而策略模式是將算法和對它們的調用分離開。這裏我們只以命令模式來說明問題。
If(condition1)
{
//condition1下的行爲
doThing1();
}
else if(condition2)
{
//condition2下的行爲
doThing2();
}
else if(condition3)
{
//condition3下的行爲
doThing3();
}
……
命令模式可以方便的對上面的代碼進行優化:
public interface Common
{
public void doThing();
}
public class Common1 implements Common
{
public void doThing()
{
//condition1下的行爲
doThing1();
}
}
public class Common2 implements Common
{
public void doThing()
{
//condition2下的行爲
doThing2();
}
}
public class Common13implements Common
{
public void doThing()
{
//condition3下的行爲
doThing3();
}
}
客戶端:
Common common;
If(condition1) common = new Common1();
else if(condition2) common = new Common2();
else if(condition3) common = new Common3();
common.doThing();
命令模式通過將行爲從調用者那裏分離出來,達到了下面幾個目的:第一,分離關注,對各個行爲進行單獨的關注,減少錯誤的出現。不管是對行爲類還是它的調用者,都變得簡單。第二,行爲類通過對接口的實現,使得它們的調用者可以對它們進行動態綁定,增加了程序的靈活性和擴展性。
代理模式將一個類的核心功能和它的附加功能區別開來,分別放在不同的類裏面,從而使每一個類的功能更加單一。
Public interface ProxyInterface
{
public void doing();
}
public class MainClass implements ProxyInterface
{
public void doing()
{
//core function
……
}
}
public class ProxyClass implements ProxyInterface
{
private ProxyInterface core = new MainClass();
public void doing()
{
//appending to do
……
//main function
core.doing();
}
}
我們可以看到,通過代理模式,上面的MainClass類用來實現核心功能,而ProxyClass類用來實現附加功能,這樣使得兩個類的功能都非常簡單,易於實現。
總之,單一職責原則是一個既簡單又實用的原則。我們遵守了這一原則,可能會多寫一些類和代碼,但磨刀不誤砍柴工。該原則既有利於我們編碼思路的清晰,又大大增強了代碼的可維護性和擴展性。
還等什麼呢?
這個原則是最簡單、最容易理解,卻是最不容易做到的事情。這個原則的道理誰都理解,可是在實踐中呢?
我們來看一個例子:
if(action.equals("load")&&tab.equals("1")){
request.setAttribute("tabId",tab);
form.set("tabId",tab);
speciManager.loadIncrement(actionForm, request, tab);
}
if(action.equals("Save")&&tab.equals("1")){
System.out.println("inter increment save action");
……
request.setAttribute("tabId",tab);
}
if(action.equals("load")&&tab.equals("2")){
request.setAttribute("tabId",tab);
form.set("tabId",tab);
speciManager.loadMeasureMent(actionForm, request, tab);
}
if(action.equals("Save")&&tab.equals("2")){
……
System.out.println("inter increment save action");
speciManager.loadIncrement(actionForm, request, tab);
form.set("tabId",tab);
request.setAttribute("tabId",tab);
}
一看就知道這個類做了太多的工作,它既要load一個tab爲1的頁面和一個tab爲2的頁面;又要save一個tab爲1頁面和一個tab爲2的頁面。這個類的代碼我只截取了裏面很少的一部分,絕大部分的代碼我都省略掉了。這段代碼寫到最後是越來越混亂,直到最後失敗。
對照着這個例子,我們再來分析一下爲什麼要遵守單一職責願則:
第一、有助於我們分析和編碼的思路的清晰。當你的代碼裏有了三層或以上的if語句或for語句的嵌套的時候,你不要跟我說,你已經把問題分析得很清楚了。多層嵌套的if或for語句只能說明你還沒有把問題分析清楚。
第二、使我們的編碼、測試和維護變得簡單。
第三、將一個個複雜的問題簡單化以後,易於代碼的重用。當你的代碼的多個功能攪和在一起的時候,你是沒辦法考慮代碼的重用的,因爲你的每一處代碼都有不同。
第四、易於系統的擴展。
好了,在這裏一二三四的列舉單一職責的原則不管用,我們需要看看實際的效果纔好。現在我們就來看看模式是怎麼來遵守這一原則的:
首先,我們來看簡單工廠模式。工廠類只有一個功能,就是產生一個個的對象產品。就這麼一個簡單的功能,但如果我們不把它拿出來,在客戶端就會出現這樣的代碼:
if(type.equals(“apple”))
{
Apple apple = new Apple();
……
}
else if(type.equals(“orange”))
{
Orange orange = new Orange();
……
}
else if(type.equals(“Banana”))
{
Banana banana = new Banana();
……
}
有了工廠,我們的客戶端就變成這樣:
Fruit fruit = Factory.getInstance(type);
……
我們的客戶端調用起來多麼的簡單,而且系統擴展起來也與客戶端無關。
我們再來看模板方法模式。
public abstract class Template {
public void totalAction()
{
commonAction();
differentAction();
}
private void commonAction()
{
//......
}
public abstract void differentAction();
}
這是一個模板類,它只做了一件事,就是所有子類的共同行爲;然後去由它的子類單獨完成自己的不同的行爲。
這樣的蓄意讓類的職責單一,擁有的好處是:第一、所有的子類的共同行爲,只在模板類裏構造一次,實現了代碼的重用。第二、將各子類不同的行爲分配到各子類裏去,使得子類極爲簡單,易於實現。
命令模式和策略模式的原理都相同,命令模式是對行爲的封裝,而策略模式是對算法的封裝。兩者都是要把相同的關注點和對他們的調用分離開,如命令模式是將行爲和對它們的調用分離開,而策略模式是將算法和對它們的調用分離開。這裏我們只以命令模式來說明問題。
If(condition1)
{
//condition1下的行爲
doThing1();
}
else if(condition2)
{
//condition2下的行爲
doThing2();
}
else if(condition3)
{
//condition3下的行爲
doThing3();
}
……
命令模式可以方便的對上面的代碼進行優化:
public interface Common
{
public void doThing();
}
public class Common1 implements Common
{
public void doThing()
{
//condition1下的行爲
doThing1();
}
}
public class Common2 implements Common
{
public void doThing()
{
//condition2下的行爲
doThing2();
}
}
public class Common13implements Common
{
public void doThing()
{
//condition3下的行爲
doThing3();
}
}
客戶端:
Common common;
If(condition1) common = new Common1();
else if(condition2) common = new Common2();
else if(condition3) common = new Common3();
common.doThing();
命令模式通過將行爲從調用者那裏分離出來,達到了下面幾個目的:第一,分離關注,對各個行爲進行單獨的關注,減少錯誤的出現。不管是對行爲類還是它的調用者,都變得簡單。第二,行爲類通過對接口的實現,使得它們的調用者可以對它們進行動態綁定,增加了程序的靈活性和擴展性。
代理模式將一個類的核心功能和它的附加功能區別開來,分別放在不同的類裏面,從而使每一個類的功能更加單一。
Public interface ProxyInterface
{
public void doing();
}
public class MainClass implements ProxyInterface
{
public void doing()
{
//core function
……
}
}
public class ProxyClass implements ProxyInterface
{
private ProxyInterface core = new MainClass();
public void doing()
{
//appending to do
……
//main function
core.doing();
}
}
我們可以看到,通過代理模式,上面的MainClass類用來實現核心功能,而ProxyClass類用來實現附加功能,這樣使得兩個類的功能都非常簡單,易於實現。
總之,單一職責原則是一個既簡單又實用的原則。我們遵守了這一原則,可能會多寫一些類和代碼,但磨刀不誤砍柴工。該原則既有利於我們編碼思路的清晰,又大大增強了代碼的可維護性和擴展性。
還等什麼呢?
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.