一直困惑於:
如何設計寫好一個類?
什麼樣的類算是設計比較的好?
前面學習了軟體首要技術革命——管理複雜度,以及設計上的一些原則。
對管理複雜度,我非常崇拜;比較笨同一時間東西太多我跟本關注不來,我非常討厭複雜的事情,
寫程式我討厭太長的函數太大的類太雜亂的邏輯。
學習原則顯得非常的散亂和太具理論性不具操作性;而我工作中用的最多還是如何設計寫好一個類和多個類之間互動性的問題。
在這個問題上:我時常感覺到只是一種隨意性的想當然操作,寫一個類僅僅是為了滿足當下的需求和應用,通常也只是自己使用和維護;
不用去考慮資訊隱藏\封裝\繼承\擴充\耦合\內聚等。如果一個類不能滿足要求時,要做的就是去修改這個類,直到它滿足要求為止:
函數功能不滿足修改函數功能,類功能不滿足增加一個方法來滿足等,結果就是問題可以解決,但是代碼或結構亂的一團糟;
這期間根本不用去考慮類的任何設計原則和約束,在文法範圍完成需要的功能即可。
但是我時常有種感覺這樣做是不行的,你比需讓你的代碼寫的友好有原則有規範性便於控制,
保持與平台設計一致的規範性寫出自己的風格來。
為何有這種感覺呢?
1)對工作的認識理解越來越深刻
軟體開發首要技術革命——管理複雜度;複雜的事情如果無序遲早會出亂子,永遠不變的就是變化。
2)良好的設計造就偉大的軟體產品誕生
設計模式到底有何用呢?通過近來一段時間平台學習,可以隨處可見代碼中相關設計模式的使用,
感覺很實用很優雅很美妙,那麼為何要如此設計呢,值得思考和學習。
3)閱讀別人的代碼
太亂的代碼是任何都不願意閱讀的,縱橫交錯的關係,你想改變都難,更難的是你還得跟著他們一塊亂,同流合汙還是有些痛苦。
4)做些有比較意義的事情
不能永遠站在寫幾個類實現一些簡易功能,維護別人的東西這個層次上,我也希望走的更遠更高。程式規模較大,
對於管理複雜度的要求肯定越高。如果沒有相應設計原則的遵循恐怕這個項目很容易夭折。勿以惡小而為之 勿以善小而不為。
那些破窗戶理論,溫水煮青蛙都說明了這些問題。
那麼今天要初步學習就是如何設計可以工作的類。
1 提高類的內聚性
class Program{ //命令棧操作 public void InitializeCommandStack(); public void PushCommand(); public void PopCommand(); public void ShutdownCommandStack(); //格式化輸出報表 public void InitializeReportFormat(); public void FormatReport(); public void PrintReport(); public void ShutdownReport(); //初始化全域資源 public void InitializeGlobalRes(); public Resorce getGlobalRes(); public void ShutDownGlobalDaRes(); ……}
看著樣一個類實現三種功能:命令棧操作,報表操作,全域資源管理;但是你能發現這三者之間有什麼聯絡呢?
唯一的聯絡就是被放到同一個類中,但實際上這三者之間沒有練習,屬於三個不同問題領域;內聚性非常的低,不滿足高內聚設計原則。
由此抽象的類形成了不一致的介面抽象;
很慚愧我通常就是這麼乾的:寫個通用的類,要什麼介面,往裡加函數,加成員資料就OK,而不管這些介面和資料之間有沒有聯絡。
應該做的是將不同領域的問題單獨提取出來抽象設計成一個類,實作類別功能的單一原則。(功能單一,變化單一)
2 形成一致的抽象層次
class EmployeeCensus{ //Employee層次上 public void AddEmployee(Employee employee); public void RmoveEmployee(Employee employee); //Employee屬性層次上 public void getEmployeeName(int index); public void getEmployeeAddress(int index);}
這個例子中層次是很明顯看得出來,明顯不合理。但是很慚愧:通常我是極少考慮這個層次問題。
在類內部或者子程式內部,管它什麼層次,完成既定需求就可以了;
寫著發現程式太長了,那就寫一個函數將某一段封裝起來,屬性該如何很難決定;
3 基於介面的編程
class ScheduleUtil{ public void addAlarm(); public void delAlarm(); public void addReminder(); public void delReminder(); public void Initialize(); public void setParams(); public boolean checkValid(); public Widget getWidget(); public void NotifyHost();}class AlarmWidget(){ ScheduleUtil mScheduleUtil; //mScheduleUtil.addAlarm();
}
class ReminderWidget(){
ScheduleUtil mScheduleUtil;
//mScheduleUtil.addReminder();
}
僅僅使用到此類中的幾個相關方法,卻要以以此類作為資料成員。似乎很不妥當的做法;
下面是進行統一介面的做法:
interface GeneralOperator{ public static final int OPERATOR_ADD_ALARM = 1; public static final int OPERATOR_ADD_REMINDER = 2; public static final int OPERATOR_CANCEL_ALARM = 3; public static final int OPERATOR_CANCEL_REMINDER = 4; public static final int OPERATOR_GET_TIME = 5; public static final int OPERATOR_GET_WEEK = 6; //提供一個介面統一處理相關的操作需求 public Object uniInteract(int operatorCmd);}class ScheduleUtil implements GeneralOperator{ @Override public Object uniInteract(int operatorCmd) { //執行命令參數相應操作 }}class AlarmWidget(){ GeneralOperator mScheduleUtil; //mScheduleUtil.uniInteract(GeneralOperator.OPERATOR_ADD_ALARM);}class ReminderWidget(){ GeneralOperator mScheduleUtil; //mScheduleUtil.uniInteract(GeneralOperator.OPERATOR_ADD_REMINDER);}
軟體設計的原則很多很有用,這裡就是要先給自己提個醒,軟體設計代碼編寫不能隨意想當然而為之,
要站在一個較高的層面上分析設計!
以我目前的實踐經驗還不足以能對對這些原則加以能充分的理解和說明,學習中……
這些原則可參考:寫的非常棒!
http://www.cnblogs.com/areliang/archive/2006/03/07/345111.html
http://coolshell.cn/articles/4535.html
代碼大全裡面核對錶——類的品質:
抽象
類是否有一個中心目地
介面清晰簡單明了
介面是否一致的抽象
……
封裝
類的成員訪問性降到最小
隱藏實現細節
封裝對其他類依賴部分
避免考慮使用者如何使用類來設計類
……
繼承:
is-a關係,衍生類別遵循LSP原則
……