### 一、開篇
?????? 其實我本來不是打算把系統架構中的一些設計模式單獨抽出來講解的,因為很多的好朋友也比較關注這方面的內容,所以我想通過我理解及平時項目中應用到的一
些常見的設計模式,拿出來給大家做個簡單講解,我這里只是拋磚引玉,如果某個地方講解的不正確或者不詳細,請大家批評指出。園子里面的很多的大牛寫的設計模式
都非常的經典,我這里寫可能有點班門弄斧的感覺,不過我還是決定把它寫出來,希望能對初學者有一定的幫助和指導的作用。當然我這里如果說某個地方解釋的有問
題或者說是某個地方寫的不符合邏輯之處,還請大家多多指出,提出寶貴意見。
?????? 軟件工程中其實有很多總結性的話語,比如說軟件=算法+數據結構等等這樣的描述,當然我們這里可能算法就是泛指一些軟件中的編程方法了,設計模式怎么去
理解呢?為什么要有設計模式?它能帶來什么?等等這些都是我們需要討論的問題。首先我們需要知道設計模式能帶來什么。可能這才是我們學習它的主要原因,如果
說不能為我們在書寫軟件的過程中帶來更方面的好處,那我們也不會使用和學習它。
?????? 設計模式是什么?
?????? 設計模式可以簡單的理解為解決某一系列問題的完美的解決方案。我們在軟件開發的過程中經常遇到設計功能實現的問題,而設計模式正是為了解決軟件設計功能
實現時遇到的某一類問題的解決方案。因為一般情況下來說,我們在某個軟件功能的開發過程中遇到的功能設計問題,可能是前人很早就遇到過的問題,所以通過這種
設計模式的方式來解決,能讓我們在軟件實現的過程中少走彎路,或者說是給我們的軟件設計帶來很好的靈活性和適應性。
?????? 設計模式帶來了什么?
?????? 設計模式是源于實踐,并且每種設計模式都包含了一個問題描述,問題涉及到的參與者并且提供了一個實際的解決方案。設計模式的好處我們可以通過下圖來簡單
說明:
???????[](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/0526b70f3950_F181/image_2.png)?當然我這里可能總結還不完全,還請大家補充,我會更新這里面的內容。當然設
計模式帶來了這么多的好處,所以我們學習設計模式就顯得比較必要了,也是從事軟件開發及設計必須掌握的基本技能之一。
?????? 設計模式的簡單分類:
???????[](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/0526b70f3950_F181/image_4.png)?當然這里可以簡單的分為這3大類,下面我們在講述的過程中將會分別講解,當然我這里是以創建型模
式開始講解,我想創建型模式也是大家項目中必備的吧?下面我就從創建型模式先來講解。
### 二、摘要
?????? 本文將主要講解創建型模式中的單例模式先來講解,因為單例模式是最簡單也是最容易理解的設計模式,上手快,易使用的設計模式。本文將從下面的流程來講解
單例模式,后面講述的設計模式也將使用這樣的方式。
?????? 1、什么是單例模式?
?????? 2、單例模式的應用場景。
?????? 3、舉例說明單例模式的使用。
?????? 4、總結單例模式的用法。
### 三、本文大綱
?????? a、開篇。
?????? b、摘要。
?????? c、本文大綱。
?????? d、單例模式的簡介。
?????? e、相關應用場景分析。
?????? f、本文總結。
?????? g、系列進度。
?????? h、下篇預告。
### 四、單例模式的簡介
?????? 本章我們將來講述下單例模式的使用,首先我們來看看單例模式的定義:
?????? 單例模式:是一種軟件設計中常用的設計模式,主要是用來控制某個類必須在某個應用程序中只能有一個實例存在。
?????? 有時候我們需要確保整個系統中只有某個類的一個實例存在,這樣有利于我們協調控制系統的行為。例如:我們在某個系統中使用了發送短信的這樣的服務,那么
我們可能希望通過單一的短信服務類的實例,而不是多個對象實例完成短信的發送服務。這時我們可以通過單例模式來完成。
???????[](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/0526b70f3950_F181/image_8.png)?上圖簡單描述了單例模式應用的位置。
??????? 我們看看單例模式的幾種實現方式:
????????[](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/0526b70f3950_F181/image_12.png)
??????? 下面我們來舉例說明下這2種方式的實現。
??????? 1、外部控制的方式
?
~~~
public class Instance
{
private List<SendMessage> lists = new List<SendMessage>();
private SendMessage sendInstance;
public SendMessage SInstance
{
get
{
return sendInstance;
}
}
public void InstanceMethod()
{
if (lists.Count == 0)
{
sendInstance = new SendMessage();
lists.Add(sendInstance);
}
else
{
sendInstance = lists[0];
}
}
}
~~~
?????? 2、內部控制方式
?
~~~
public class Instance1
{
private static SendMessage sendInstance;
private static object _lock = new object();
protected Instance1()
{
}
public static SendMessage SInstance
{
get
{
lock (_lock)
{
if (sendInstance == null)
sendInstance = new SendMessage();
return sendInstance;
}
}
}
}
~~~
??????? 這里有幾點需要注意的地方,對于第二種方式有幾個地方需要說明下,首先是要控制全局只有一個實例的類,請定義成靜態實例,這樣可以確保只有一個實例對
象,其次,這個對象的構造函數請聲明成保護類型的成員,這樣可以屏蔽通過直接實例化的形式來訪問。通過這樣的形式,客戶可以不需要知道某個單例實例對象的內
部實現細節。一般情況下滿足上面的2點需求就可以完成全局唯一訪問入口的控制。當然可能在多線程的情況下采用這樣的形式還會有一定的弊端,當然我們這里也簡單
的講解下相應的控制方案。方案如下:
?
~~~
public class CoolInstance
{
private CoolInstance()
{
}
public static readonly CoolInstance Instance = new CoolInstance();
}
~~~
?? ?
?
?????? 看吧很簡單吧,當然我們這里來簡單解釋下原理:
?????? 1、我們先把構造函數聲明為私有的構造函數,這樣我們能夠屏蔽外部通過實例化的形式訪問內部的成員函數。所有的成員函數的訪問必須通過靜態成員Instance
來完成訪問。
?????? 2、這段代碼通過定義公共、靜態、只讀的成員相當于在類被第一次使用時執行構造,由于是只讀的,所以一旦構造后不允許修改,就不用擔心不安全的問題。
??????? 相信對上面的介紹大家應該基本上知道單例模式的應用了,那么下面我們來看看項目中的實際應用場景及用法。
### 五、相關應用場景講解
??????? 1、場景短信及郵件發送服務
??????? 那么我們將采用上面介紹的最“COOL”的方式來進行控制,提供發送短信及發送郵件的服務。
?
~~~
public class CoolInstance
{
private CoolInstance()
{
}
public static readonly CoolInstance Instance = new CoolInstance();
/// <summary>
/// 發送手機短信
/// </summary>
public bool SendMessage(string telNumber,string content)
{
return true;
}
/// <summary>
/// 發送郵件
/// </summary>
/// <param name="content"></param>
/// <param name="toMail"></param>
public bool SendMail(string content,string toMail)
{
return true;
}
}
~~~
??????? 我們再來看看調用類中如何書寫完成調用。例如我們有個訂單類,當有人新下訂單時,將給賣家發送短信提醒功能。
?
~~~
/// <summary>
/// 訂單業務
/// </summary>
public class Order
{
public int Save()
{
//先是將訂單的相關信息生成,
this.InitOrderInfo();
//執行訂單的持久化方法
int count= this.Add();
//發送短信
CoolInstance.Instance.SendMessage(string.Empty, string.Empty);
//發送郵件
CoolInstance.Instance.SendMail(string.Empty, string.Empty);
return count;
}
/// <summary>
/// 初始化訂單信息
/// </summary>
private void InitOrderInfo()
{
}
/// <summary>
/// 新增訂單信息
/// </summary>
/// <returns></returns>
private int Add()
{
return 0;
}
}
~~~
?? ? ??
?
??????? 這樣我們就完成了短信發送服務及郵件發送服務的控制。主要還是根據自己的業務需要。
??????? 2、例如我們現在提供一個系統日志服務或者打印或者掃描的服務,我們希望全局只有一個訪問入口,那么我們就可以通過這樣的單例模式來實現這樣的需求。
?
~~~
public class PrintHelper
{
#region 構造函數
private PrintHelper()
{
}
public static readonly PrintHelper Instance = new PrintHelper();
#endregion
#region 打印服務
/// <summary>
/// 直接打印服務
/// </summary>
/// <returns></returns>
public bool Print()
{
return true;
}
/// <summary>
/// 打印預覽
/// </summary>
/// <returns></returns>
public bool PrintPreview()
{
return true;
}
#endregion
}
~~~
??????? 具體的調用類我就不寫相應的代碼,都和上面的形式類同,下面我們講解下可能更特殊的需求,有時候我們可能需要更新我們創建的唯一實例,這時我們如何控
制單例實例對象的更新呢,有時候可能我們有這樣的需求。下面我們來看看如何實現這樣的需求。
??????? 3、可更新單例對象的場景
??????? 首先我們先說下什么情況下會遇到這樣的更新方式呢?例如我們想在單例模式的類的構造函數是帶有一定參數的情形時:
?
~~~
public class UpdateHelper
{
private string type = string.Empty;
private static object _lock = new object();
private static UpdateHelper instance;
private UpdateHelper(string valueType)
{
type = valueType;
}
public static UpdateHelper Instance
{
get
{
lock (_lock)
{
if (instance == null)
{
//如果這里有多個條件需求的話,可能寫起來會比較復雜,那么有更好的方式來處理嗎?
instance = new UpdateHelper("test!");
}
return instance;
}
}
}
}
~~~
??????? 那么我們來分析幾種辦法,有沒有更好的辦法來處理呢?
??????? 1、首先我們不能手動實例化,所以我們沒有辦法動態傳入構造函數參數,只能在類的內部指定這個參數,但是有時候我們需要動態的更新這個參數,那么這樣的
形式顯然就沒有辦法實現。
??????? 2、通過屬性的方式,來動態的設置屬性的內容來完成輸出參數的改變,但是這樣的方式可能太過自由,無法滿足單例模式的初衷。
??????? 3、接口方式,因為接口必須要靠類來實現,所以更不靠譜,可以不考慮這樣的方式。
??????? 4、通過Attribute的方式來將信息動態的注入到構造函數中,但是怎么說這樣的方式是不是太興師動眾了呢?畢竟單例模式本來就是很簡單的。
??????? 5、通過配置文件,通過config文件配置節點的形式來動態的配置相關信息,實現更新實例對象內容的情況。
??????? 通過上面的5種情況的分析,那么通過2、4、5可以實現這個要求,但是對比相應的代價來說,5的方式是最靈活也是最符合單例模式本來的規范要求,相對來說
成本和代價也可以接收。
?
~~~
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.Web>
<add key="ssss" >value</add>
</system.Web>
</configuration>
~~~
?
???????? 那么我們上面的單力模型中的代碼只需要稍微的變化下即可,請看如下代碼:
?
~~~
public class UpdateHelper
{
private string type = string.Empty;
private static object _lock = new object();
private static UpdateHelper instance;
private UpdateHelper(string valueType)
{
type = valueType;
}
public static UpdateHelper Instance
{
get
{
lock (_lock)
{
if (instance == null)
{
//如果這里有多個條件需求的話,可能寫起來會比較復雜,那么有更好的方式來處理嗎?
instance = new UpdateHelper(System.Configuration.ConfigurationManager.AppSettings["ssss"].ToString());
}
return instance;
}
}
}
}
~~~
??????? 我想到這里大家都對單例模式有個簡單的認識了,本文的內容就講到這里。我們來回顧下我們講述的內容:
????????[](http://images.cnblogs.com/cnblogs_com/hegezhou_hot/WindowsLiveWriter/0526b70f3950_F181/image_14.png)
### 六、本文總結
??????? 本文主要講述了創建型模式中的單例模式,單例模式主要是用來控制系統中的某個類的實例的數量及全局的訪問入口點。我們主要講述了實現單例模式的方式,
分為外部方式及內部方式,當然我們現在采用的方式都是內部方式,還講述了線程安全的單例模式及帶有參數的構造函數的情況,根據配置文件來實現參數值的動態配
置的情況。希望本文的講解能對不熟悉設計模式的同仁能夠了解知道單例模式的應用,而對已熟知單例模式的同仁可以溫故而知新,我會努力寫好這個系列,當然我這
里可能在大牛的面前可能是班門弄斧吧,不過我會繼續努力,爭取寫出讓大家一看就明白的設計模式系列。本文錯誤之處再所難免,還請大家批評之處,我會繼續改
進。
### 七、系列進度
##### ??????? 創建型
??????? 1、[系統架構技能之設計模式-單件模式](http://www.cnblogs.com/hegezhou_hot/archive/2010/10/02/1841390.html)
??????? 2、系統架構技能之設計模式-工廠模式
??????? 3、系統架構技能之設計模式-抽象工廠模式
??????? 4、系統架構技能之設計模式-創建者模式
??????? 5、系統架構技能之設計模式-原型模式
##### ??????? 結構型
??????? 1、系統架構技能之設計模式-組合模式
??????? 2、系統架構技能之設計模式-外觀模式
??????? 3、系統架構技能之設計模式-適配器模式
??????? 4、系統架構技能之設計模式-橋模式
??????? 5、系統架構技能之設計模式-裝飾模式
??????? 6、系統架構技能之設計模式-享元模式
??????? 7、系統架構技能之設計模式-代理模式
##### ??????? 行為型
??????? 1、系統架構技能之設計模式-命令模式
??????? 2、系統架構技能之設計模式-觀察者模式
??????? 3、系統架構技能之設計模式-策略模式
??????? 4、系統架構技能之設計模式-職責模式
??????? 5、系統架構技能之設計模式-模板模式
??????? 6、系統架構技能之設計模式-中介者模式
??????? 7、系統架構技能之設計模式-解釋器模式
### 八、下篇預告
??????? 下篇我們將會介紹我們大家最熟知的工程模式,當然我會更多的結合實例來講解每個設計模式的應用場景及具體的實例,來更清晰的描述什么情況下用什么模
式,及每個模式之間的區別。大家的支持就是我書寫的動力,希望大家多多支持我吧!