常用的设计模式
--什么是設計模式?設計模式有哪幾種分類?每類模式重點解決什么問題?
設計模式:是一套被反復使用、多數人知曉的、經過分類編目的、代碼設計經驗的總結。使用設計模式是為了可重用代碼、讓代碼更容易被他人理解、保證代碼可靠性。
--根據模式的目的,將模式分為三大類:
? 創建型模式:抽象化了實例化過程。它們幫助一個系統獨立于如何創建、組合和表示它的那些對象。
? 結構性模式:涉及到如何組合類和對象以獲得更大的結構。結構型模式采用繼承機制來組合接口或實現。
? 行為型模式:涉及到算法和對象間職責的分配。行為模式不僅描述對象或類的模式,還描述它們之間的通信模式。這些模式刻畫了在運行時難以跟蹤的復雜的控制流。
常見的幾個設計模式及其用例:
一 單例模式(Singleton)
詳見之前的單例模式
二.適配器模式:將一個類的接口轉換成客戶希望的另外一個接口。
1. 模式的問題:
Adapter模式使得原本由于接口不兼容而不能一起工作的那些類可以在一起工作。
2. 解決方案:通過添加一個適配器來包裝一個需要適配的對象,把原接口轉換成目標接口。
3. 模式中的角色
3.1 目標接口(Target):客戶所期待的接口。目標可以是具體的或抽象的類,也可以是接口。
3.2 需要適配的類(Adaptee):需要適配的類或適配者類。
3.3 適配器(Adapter):通過包裝一個需要適配的對象,把原接口轉換成目標接口。
4. 使用條件:
--系統需要使用現有的類,而此類的接口不符合系統的需要。
--?想要建立一個可以重復使用的類,用于與一些彼此之間沒有太大關聯的一些類,包括一些可能在將來引進的類一起工作。這些源類不一定有很復雜的接口。
--兩個類所做的事情相同或相似,但是具有不同接口的時候。
--?舊的系統開發的類已經實現了一些功能,但是客戶端卻只能以另外接口的形式訪問,但我們不希望手動更改原有類的時候。
--?使用第三方組件,組件接口定義和自己定義的不同,不希望修改自己的接口,但是要使用第三方組件接口的功能。
5.模式優缺點:
優點:
--?通過適配器,客戶端可以調用同一接口,因而對客戶端來說是透明的。這樣做更簡單、更直接、更緊湊。
--?復用了現存的類,解決了現存類和復用環境要求不一致的問題。
--?將目標類和適配者類解耦,通過引入一個適配器類重用現有的適配者類,而無需修改原有代碼。
--?一個對象適配器可以把多個不同的適配者類適配到同一個目標,也就是說,同一個適配器可以把適配者類和它的子類都適配到目標接口。
缺點: 對于對象適配器來說,更換適配器的實現過程比較復雜。
6. 模式解讀
注:在GoF的設計模式中,對適配器模式講了兩種類型,類適配器模式和對象適配器模式。由于類適配器模式通過多重繼承對一個接口與另一個接口進行匹配,而C#、java等語言都不支持多重繼承,因而這里只是介紹對象適配器。
4.1 適配器模式的類圖
4.2 適配器模式的代碼實現
/// <summary>/// 定義客戶端期待的接口/// </summary>public class Target{/// <summary>/// 使用virtual修飾以便子類可以重寫/// </summary>public virtual void Request(){Console.WriteLine("This is a common request");}}/// <summary>/// 定義需要適配的類/// </summary>public class Adaptee{public void SpecificRequest(){Console.WriteLine("This is a special request.");}}/// <summary>/// 定義適配器/// </summary>public class Adapter:Target{// 建立一個私有的Adeptee對象private Adaptee adaptee = new Adaptee();/// <summary>/// 通過重寫,表面上調用Request()方法,變成了實際調用SpecificRequest()/// </summary>public override void Request(){adaptee.SpecificRequest();}}4.3 客戶端代碼
class Program{static void Main(string[] args){// 對客戶端來說,調用的就是Target的Request()Target target = new Adapter();target.Request();Console.Read();}}運行結果:This is a special request.
三 組合模式
概述:允許你將對象組合成樹型結構來表現“整體/部分”層次結構。組合能讓客戶以一致的方式處理個別對象以及對象組合。
1.解決的問題:將對象組合成樹形結構以表示整體與部分的層次結構,使得用戶對單個對象和組合對象的使用具有一致性。
2.解決方案:組合模式的關鍵就是引入了抽象類,它既可以代表圖元,又可以代表圖元的容器。在圖形系統中這個類就是Gtsphic,它聲明一些與特定圖形對象相關的操作,如Draw。同時它也聲明了所有的組合對象共享的一些操作,如一些操作用于訪問和管理它的子部件。
3.使用條件:
-- 想表示對象的部分-整體層次結構。
--?希望用戶忽略組合對象與單個對象的不同,用戶將統一地使用組合結構中的所有對象。
4.效果:
-- 組合模式可以很容易的增加新的組件。
--?使用組合模式可以使客戶端變的很容易設計,因為客戶端可以對組合和葉節點一視同仁。
算術表達式確實是組合的例子。算術表達式包括操作數、操作符和另一個操作數。操作數可以是數字,也可以是另一個表達式。這樣,2+3和(2+3)+(4*6)都是合法的表達式。
圖 使用算術表達式例子的Composite模式對象圖
實現:
Component:為參加組合的對象聲明一個公共接口,不管是組合還是葉節點。
public abstract class Component {public void add(Component component) {throw new UnsupportedOperationException();}public void remove(Component component) {throw new UnsupportedOperationException();}public Component getChild(int i) {throw new UnsupportedOperationException();}public void operation() {throw new UnsupportedOperationException();} }Leaf:在組合中表示葉節點對象,葉節點沒有子節點。public class Leaf extends Component {public void operation(){//your code } }Composite:表示參加組合的有子對象的對象,并給出樹枝構件的行為。public class Composite extends Component {ArrayList<Component> components = new ArrayList<Component>();public void add(Component component){components.add(component);}public void remove(Component component){components.remove(component);}public Component getChild(int i){return components.get(i);}public void operation(){for (Component component : components){component.operation();}} }四 工廠模式
這里指講解一下簡單工廠模式,工廠模式有三種。
簡單工廠模式:
1.解決的問題:簡單工廠模式根據提供給他的數據,返回幾個可能類中的一個類的實例。
在軟件開發中我們經常會碰到一系列相關的對象需要創建,如果按照常規做法我們就要為不同的對象創建編寫不同的代碼,復用性和可維護性都降低了。而且這些相關對象創建的方式也許不同,那么客戶代碼創建的時候就要針對不同的對象編碼,對象創建的方式還是一個容易改變的地方。基于這樣的情況提出了抽象工廠模式,抽象工廠模式為創建一系列相關對象提供了統一的接口,客戶只要調用這個接口即可,封裝了變化,隔離了變化,讓客戶代碼穩定起來。
解決方案:通過用戶調用一個工廠類來為自己生成所需對象。
5.模式UML圖????
下面是簡單工廠模式的示意性UML圖: 如上圖,簡單工廠模式UML我畫了兩種,詳細如下: ① 只有一個產品對象的簡單工廠模式。 ② 帶有一個抽象產品對象的簡單工廠模式。 模式參與者 工廠(Factory)角色:接受客戶端的請求,通過請求負責創建相應的產品對象。 抽象產品(AbstractProduct)角色: 是工廠模式所創建對象的父類或是共同擁有的接口。可是抽象類或接口。 具體產品(ConcreteProduct)對象:工廠模式所創建的對象都是這個角色的實例。五.代理模式
概述:意圖是為其他對象提供一種代理以控制對這個對象的訪問,簡而言之就是用一個對象來代表另一個對象。
1.解決的問題:由于一些對象創建和實例化需要占用大量系統資源,但我們并不能確定用戶一定會調用該對象,所以通過延遲對象實例化來減緩系統資源的消耗。
2.解決方案:用一個花費代價少的代理來代替需要的對象,直到我們確實需要這個對象時才對他進行創建和初始化。
3.種類
--遠程代理,為一個對象在不同的地址空間提供局部代表
--虛代理 根據需要創建開銷很大的對象。 --保護代理 控制隊員是對象的訪問。保護代理用于對象應該有不同的訪問權限的時候。 --?智能指引 取代了簡單的指針,他在訪問對象時執行一些附加操作。主要的用途包括:對指向實際對象的引用計數,這樣當該對象沒有引用時,可以自動釋放。當第一次引用一個持久對象時,將它裝入內存。在訪問一個實際對象前,檢查是否已經鎖定了它,以確保其他對象不能改變它。這里給出兩個使用該模式的例子:
應用一:虛擬代理????
例如:word文檔打開
Word文檔通常會含有鏈接、圖片、表格等對象,但是并不是每次剛打開word時都要創建和實例化這些對象,特別是實例化圖片對象很消耗資源。事實上,我們沒必要實例化所有圖片,當我們在查看word時,每次只是看到其中的一部分,所以沒有必要實例化所有資源,可以使用一個虛代理物件,代替圖片被載入,來加快打開文檔速度,當我們看下一頁時再載入圖片也不遲。
類圖如圖所示:
? 如上圖所示,當文檔被開啟時, ProxyImage代理代替RealImage物件被載入,在還沒卷動至圖片顯示處時,也就是還沒有調用 ProxyImage的Draw()時,圖片并不會被載入,因而可以加速文檔的開啟;如果需要顯示圖片了, ProxyImage的 Draw()會被調用,而這時才真正創建RealImage物件,以從硬盤中載入圖片。
主要類代碼:
public interface Image //Image公共接口 {public abstract void Draw();}//ProxyImage類實現Image接口 public class ProxyImage implements Image {private RealImage realimage;public void Draw() {If(realimage==NULL) {Realimage=new RealImage(); } realimage.Draw(); }}//RealImage類實現Image接口 public class RealImage implements Image{ public void Draw() { Console.WriteLine(“載入圖片……”);}}主程序 public class App{public static void Main(){ProxyImage proxy = new ProxyImage();proxy.Draw();}}應用二:遠程訪問
例子:遠程數學運算訪問
本地客戶程序需要調用遠程服務器提供的數學運算服務,也就是說數學運算服務和客戶程序不在同一個地址空間之內,我們現在要面對的是跨越Internet這樣一個網絡障礙:這時候調用數學運算服務就沒有下面那么簡單了,因為我們更多的還要去考慮網絡的問題,對接收到的結果解包等一系列操作。為了避免由于網絡等障礙引起的復雜性,引用Proxy模式,用一個本地的代理來代替遠程數學運算類打點一切,即為我們的系統引入了一層間接層,示意圖如下
?設計的類圖如下:
?
如上圖所示:我們在ProxMath中對實現數據類的訪問,讓ProxyMath來代替網絡上的RealMath類,這樣我們看到ProxMathy就好像是本地RealMath類,它與客戶程序處在了同一地址空間內
主要代碼
public interface Math //Math公共接口 {public abstract double Add(double x,double y);public abstract double Sub(double x,double y);public abstract double Mul(double x,double y);public abstract double Dev(double x,double y);}public class ProxyMath implements Math //Proxy類,繼承于Math {private RealMath realmath = new RealMath();//Proxy類中不光有調用Math類的方法,還包含一些網絡通信,與遠程服務器交換數據,此處省略。public double Add(double x,double y){return math.Add(x,y);}public double Sub(double x,double y){return realmath.Sub(x,y);}public double Mul(double x,double y){return realmath.Mul(x,y);}public double Dev(double x,double y){return realmath.Dev(x,y);}}public class RealMath implements Math{public double Add(double x,double y){return x + y;}public double Sub(double x,double y){return x - y;}public double Mul(double x,double y){return x * y;}public double Dev(double x,double y){return x / y;}}測試主程序 public class App{public static void Main(){ProxyMath proxy = new ProxyMath();double addresult = proxy.Add(2,3);double subresult = proxy.Sub(2,3);double mulresult = proxy.Mul(2,3);double devresult = proxy.Dev(2,3);}}?
從上面的兩個例子可以概括出Proxy模式的工作原理:
首先,代理并不改變主題的接口,因為模式的用意是不讓客戶端感覺到代理的存在;
其次,代理使用委派將客戶端的調用委派給真實的主題對象,換言之,代理起到的是一個傳遞請求的作用;
第三,代理在傳遞請求之前和之后都可以執行特定的操作(如網絡通信、檢查對象是否存在等),而不是單純傳遞請求。
?
?
?
?
?
轉載于:https://www.cnblogs.com/Yogurshine/archive/2013/01/12/2858016.html
總結
- 上一篇: 有3个集合, 从其中一个集合中删除同时存
- 下一篇: Haddop学习:(一)序