結構型模式涉及到如何組合類和對象以獲得更大的結構。
結構型模式包括:適配器模式,橋接模式,裝飾者模式,組合模式,外觀模式,享元模式,代理模式
1.適配器模式
適配器:將一個類的接口轉換成客戶希望的另外一個接口,Adapter模式使得原本由於接口不兼容而不能一起工作的那些類能一起工作。比如一般購物網站都能將自己喜歡的商品加入favorite,而亞馬遜則是加入wishlist。我們想要一個統一的接口對所有網站都提供favorite接口,這時就需要用到適配器了。
abstract class OnlineShop { public abstract void favorite(); } class amazon { public void wishlist() { Console.Write("my wishlist"); } } class adaptedAmazon : OnlineShop { amazon ama = new amazon(); public override void favorite() { ama.wishlist(); } } namespace model { class Program { static void Main(string[] args) { OnlineShop shop = new adaptedAmazon(); shop.favorite(); Console.Read(); } } }
2.橋接模式
Bridge模式用來將抽象部分與它的實現部分分離,使它們都可以獨立地變化。
這個有點類似於外包公司,這個外包公司給我們提供了一個服務列表,比如服務A是給我們提供B公司的C產品,這時外包公司的服務列表就是抽象部分,B公司則負責具體的生產,外包公司不關心B公司的具體生產,但是他可以通過對B公司的產品進行定制,生成不同的服務,B公司也不關心外包公司提供什么服務,而只是關心有哪些基本的產品需要生產。
class Abstraction { protected Implementor implementor; public void SetImplementor(Implementor implementor) { this.implementor = implementor; } public virtual void Operation() { implementor.Operation(); } } class RefinedAbstraction : Abstraction { public override void Operation() { implementor.Operation(); } } abstract class Implementor { public abstract void Operation(); } class ConcreteImplementorA : Implementor { public override void Operation() { Console.WriteLine("具體實現A的方法執行"); } } class ConcreteImplementorB : Implementor { public override void Operation() { Console.WriteLine("具體實現B的方法執行"); } } namespace model { class Program { static void Main(string[] args) { Abstraction ab = new RefinedAbstraction(); ab.SetImplementor(new ConcreteImplementorA()); ab.Operation(); ab.SetImplementor(new ConcreteImplementorB()); ab.Operation(); Console.Read(); } } }
優點:
1)分離接口及其實現部分,橋接模式使你可以對不同的抽象接口和實現部分進行組合,並分別對它們進行擴充。
2)實現細節對客戶透明
3.組合模式
組合模式使得用戶對單個對象和組合對象的使用具有一致性。
比如一副圖像,它可能由很多圖元和子圖像組合而成,其中子圖像可能又由圖元和子圖像組合而成,就像一棵多叉樹。
class Graphic { private List<Graphic> _graphics = new List<Graphic>(); public void Add(Graphic graph) { _graphics.Add(graph); } public virtual void Draw() { Console.WriteLine("a graph:"); foreach (Graphic graph in _graphics) { graph.Draw(); } } } class Circle : Graphic { public override void Draw() { Console.WriteLine("a circle"); } } class Line : Graphic { public override void Draw() { Console.WriteLine("a line"); } } namespace model { class Program { static void Main(string[] args) { Graphic graph = new Graphic(); Graphic graph1 = new Graphic(); graph1.Add(new Line()); graph.Add(new Circle()); graph.Add(graph1); graph.Draw(); Console.Read(); } } }
優點:
1)簡化客戶代碼
2)使得更容易增加新類型的組件
3)使你的設計變得更加一般化
4.裝飾者模式
裝飾者模式:動態地給一個對象添加一些額外的職責。注意是給對象而不是類添加職責。
裝飾者其實就是把對象包裝了一下,把對對象額外進行的操作封裝到了一個裝飾類中。
abstract class Component { public abstract void Operation(); } class ConcreteComponent : Component { public override void Operation() { Console.WriteLine("具體對象的操作"); } } abstract class Decorator : Component { protected Component component; public override void Operation() { component.Operation(); } } class ConcreteDecoratorA : Decorator { public ConcreteDecoratorA(Component component) { this.component = component; } public override void Operation() { base.Operation(); Console.WriteLine("具體裝飾對象A的操作"); } } class ConcreteDecoratorB : Decorator { public ConcreteDecoratorB(Component component) { this.component = component; } public override void Operation() { base.Operation(); Console.WriteLine("具體裝飾對象B的操作"); } } namespace model { class Program { static void Main(string[] args) { ConcreteComponent c = new ConcreteComponent(); ConcreteDecoratorA d1 = new ConcreteDecoratorA(c); ConcreteDecoratorB d2 = new ConcreteDecoratorB(c); d1.Operation(); d2.Operation(); Console.Read(); } } }
裝飾者模式比靜態繼承靈活,可以動態的給一個對象加多個裝飾。
5.外觀模式
Facade模式為子系統中的一組接口提供一個一致的界面。
就好象我們畫一個三角形,我們要依次畫三角形的三條邊,但是我們實際上並不關心這個三角形是怎樣畫出來的,我們只想要有一個畫三角形的接口Draw,我們只要調用這個接口,就能畫出這個三角形就行了。
class SubSystemOne { public void MethodOne() { Console.WriteLine(" 子系統方法一"); } } class SubSystemTwo { public void MethodTwo() { Console.WriteLine(" 子系統方法二"); } } class SubSystemThree { public void MethodThree() { Console.WriteLine(" 子系統方法三"); } } class SubSystemFour { public void MethodFour() { Console.WriteLine(" 子系統方法四"); } } class Facade { SubSystemOne one; SubSystemTwo two; SubSystemThree three; SubSystemFour four; public Facade() { one = new SubSystemOne(); two = new SubSystemTwo(); three = new SubSystemThree(); four = new SubSystemFour(); } public void MethodA() { Console.WriteLine("\n方法組A() ---- "); one.MethodOne(); two.MethodTwo(); four.MethodFour(); } public void MethodB() { Console.WriteLine("\n方法組B() ---- "); two.MethodTwo(); three.MethodThree(); } } namespace model { class Program { static void Main(string[] args) { Facade facade = new Facade(); facade.MethodA(); facade.MethodB(); Console.Read(); } } }
優點:
1)對客戶屏蔽子系統組件
2)實現子系統與客戶之間的松耦合關系
6.享元模式
當一個應用程序使用了大量的對象,造成很大的存儲開銷,且對象的大多數狀態都可以變為外部狀態,這時應該使用Flyweight模式,刪除對象的外部狀態,以便用相對較少的共享對象取代很多對象。
比如文檔編輯器,若把編輯器中每個字符都作為一個對象顯然會造成大量的存儲開銷,可以將不同的字符作為一個實例,每個字符實例都能根據外部傳入的字體位置等信息進行繪圖。
public interface Flyweight { public void draw(Pos pos, int fontsize); } public class Character implements Flyweight { private char _charcode; /** * 構造函數,內蘊狀態作為參數傳入 * @param state */ public Character(char c){ this._charcode = char; } /** * 外蘊狀態作為參數傳入方法中,改變方法的行為, * 但是並不改變對象的內蘊狀態。 */ @Override public void draw(Pos pos, int fontsize) { System.out.println(String.format("%d%d%d",pos.x,pos.y,fontsize)); } } const int NCHARCODES = 128; public class FlyweightFactory { private Character[] _chars = new Character[NCHARCODES]; public FlyweightFactory(){ for(int i=0; i<NCHARCODES; ++i){ _chars[i]=null; } } public Flyweight factory(char c){ if(_chars[c]==null){ //如果對象不存在則創建一個新的Flyweight對象 _chars[c] = new Character(c); } return _chars[c]; } } class Program { static void Main(string[] args) { FlyweightFactory fac = new FlyweightFactory(); Character curr = fac.factory('a'); curr.show(new Pos(1,2),12); Console.Read(); } }
7.代理模式
代理模式為其他對象提供一種代理以控制對這個對象的訪問。
下面是一些需要使用代理的情形:
我們在對一個對象下達指令之前必須要先創建和初始化這個對象,對於一個比較大的對象,我們更傾向於在需要使用它的時候再去創建和初始化這個對象,我們將這個創建,初始化和使用對象的一系列操作都封裝在了代理中。
我們需要對要訪問的對象提供某種訪問保護,這時我們將對象的權限驗證和使用對象的一系列操作都封裝在代理中。
namespace model { abstract class Subject { public abstract void Request(); } class RealSubject : Subject { public override void Request() { Console.WriteLine("真實的請求"); } } class Proxy : Subject { RealSubject realSubject; public override void Request() { if (realSubject == null) { realSubject = new RealSubject(); } realSubject.Request(); } } class Program { static void Main(string[] args) { Proxy proxy = new Proxy(); proxy.Request(); Console.Read(); } } }
使用代理的常見情況:
1)遠程代理:為一個對象在不同的地址空間提供局部代表
2)虛代理:根據需要創建開銷很大的對象
3)保護代理:控制對原始對象的訪問
4)智能引用:取代了簡單的指針,在訪問對象時執行一些附加操作
