適配器模式簡介:
將一個類的接口轉換成客戶希望的另外一個接口。Adapter模式使得原本由於接口不兼容而不能一起工作的那些類可以一起工作。
在計算機編程中,適配器模式(有時候也稱包裝樣式或者包裝)將一個類的接口適配成用戶所期待的。一個適配允許通常因為接口不兼容而不能在一起工作的類工作在一起,做法是將類自己的接口包裹在一個已存在的類中。
適配器模式結構圖:
引入實例進行說明:
以日志記錄程序為Demo說明,在任何一套軟件中都會有對應的日志管理模塊,假如如果我們在開發軟件中的日記記錄采用第三方的日志組件進行日志記錄,它采用的是Log.Write("寫日志");的方式我們的程序在開發中,大量實例化日記記錄對象,采用的Log.Write()方式進行日志記錄,但是現在第三方的日志組件現在不免費了,需要收費了,於是我們打算使用一種新的日志管理模塊,只不過它提供給我們的API接口是采用Log.WriteLog("新的寫日志的方式");進行日志記錄。這個時候問題就出現了,如何應對這種遷移的變化
類適配器模式
1.原來日志的接口,采用的是Write(“寫日志”);方法
/// <summary> /// 原來的日志記錄接口 /// </summary> public interface ILogTarget { /// <summary> /// 原來的寫日志方法 /// </summary> void Write(string info); }
2.然而現在的寫日志的接口,采用的是WriteLog("寫日志");裡面實現了寫日志的新的方式:將日志寫到文件中,數據庫中
/// <summary> /// 抽象寫日志類 /// </summary> public abstract class LogAdaptee { /// <summary> /// 寫日志 /// </summary> public abstract void WriteLog(string info); }
/// <summary> /// 寫文件日志記錄 /// </summary> public class FileLog:LogAdaptee { /// <summary> /// 寫日志到文件中 /// </summary> public override void WriteLog(string info) { Console.WriteLine("記錄到文本文件:"+info); } }
/// <summary> /// 往數據庫中寫日志 /// </summary> public class DatabaseLog:LogAdaptee { /// <summary> /// 重寫寫日志方法 /// </summary> public override void WriteLog(string info) { Console.WriteLine("記錄到數據庫:"+info); } }
3.如何使用者兩個新對象中的方式,替換原來的寫日志的方式?
/// <summary> /// 采用新的寫日志的方式,寫入到數據庫中 /// </summary> public class DatabaseLogAdapter:DatabaseLog,ILogTarget { /// <summary> /// 在重寫ILogTarget接口中的的Write方法裡面調用新的寫日志的方式WriteLog /// </summary> public void Write(string info) { WriteLog(info); } } /// <summary> /// 采用新的寫日志的方式,寫入到文本文件 /// </summary> public class FileLogAdapter : FileLog, ILogTarget { /// <summary> /// 在重寫ILogTarget接口中的的Write方法裡面調用新的寫日志的方式WriteLog /// </summary> public void Write(string info) { this.WriteLog(info); } }
4.調用依據使用的原來寫日志的方法,但是確實使用的新的寫日志的方式:
/// <summary> /// 類 適配器模式(Adapter Pattern) /// </summary> class Program { static void Main(string[] args) { ILogTarget dbLog = new DatabaseLogAdapter(); dbLog.Write("程序啟動成功"); dbLog = new FileLogAdapter(); dbLog.Write("程序啟動成功"); } }
對象適配器模式
1.方式采用的是類適配器的方式實現了新的日志功能的遷移變化,下面我們使用對象適配器,可以區別發現兩種方式的特別之處。原來寫日志的方法依舊不變:Write("寫日志");
/// <summary> /// 原來的日志記錄接口 /// </summary> public interface ILogTarget { /// <summary> /// 原來的寫日志方法 /// </summary> void Write(string info); }
2.現在的寫日志的接口,采用的是WriteLog("寫日志");裡面實現了寫日志的新的方式:將日志寫到文件中,數據庫中:
/// <summary> /// 抽象寫日志類 /// </summary> public abstract class LogAdaptee { /// <summary> /// 寫日志 /// </summary> public abstract void WriteLog(string info); }
/// <summary> /// 寫文件日志記錄 /// </summary> public class FileLog:LogAdaptee { /// <summary> /// 寫日志到文件中 /// </summary> public override void WriteLog(string info) { Console.WriteLine("記錄到文本文件:"+info); } }
/// <summary> /// 往數據庫中寫日志 /// </summary> public class DatabaseLog:LogAdaptee { /// <summary> /// 重寫寫日志方法 /// </summary> public override void WriteLog(string info) { Console.WriteLine("記錄到數據庫:"+info); } }
3.上面我們添加了FileLogAdapter 類,DatabaseLogAdapter類,繼承了FileLog,DatabaseLog, ILogTarget接口,重寫Write方法裡面調用新的寫日志的方式WriteLog,使用這樣的方式進行了遷移變化。下面使用對象適配:
/// <summary> /// 對象適配,繼承ILogTarget,裡面有LogAdaptee抽象日志類對象。 /// </summary> public class LogAdapter:ILogTarget { /// <summary> /// 抽象寫日志類 /// </summary> private LogAdaptee _adaptee; public LogAdapter(LogAdaptee adaptee) { this._adaptee = adaptee; } public void Write(string info) { _adaptee.WriteLog(info); } }
4.在程序中的調用:
/// <summary> /// 對象適配器模式(Adapter Pattern) /// </summary> class Program { static void Main(string[] args) { ILogTarget dbLog = new LogAdapter(new DatabaseLog()); dbLog.Write("程序啟動成功"); ILogTarget fileLog = new LogAdapter(new FileLog()); fileLog.Write("程序啟動成功"); } }
比較兩者的遷移變化,在類適配方式中,我們得到的適配器類DatabaseLogAdapter和FileLogAdapter具有它所繼承的父類的所有的行為,同時也具有接口ILogTarget的所有行為,這樣其實是違背了面向對象設計原則中的類的單一職責原則,而對象適配器則更符合面向對象的精神,所以在實際應用中不太推薦類適配這種方式。假設我們要適配出來的類在記錄日志時同時寫入文件和數據庫,那麼用對象適配器我們會這樣去寫:
/// <summary> /// 對象適配,繼承ILogTarget,裡面有LogAdaptee抽象日志類對象。 /// </summary> public class LogAdapter:ILogTarget { /// <summary> /// 抽象寫日志類 /// </summary> private LogAdaptee _adapteed; /// <summary> /// 抽象寫日志類 /// </summary> private LogAdaptee _adapteef; public LogAdapter(LogAdaptee adapteed, LogAdaptee adapteef) { this._adapteed = adapteed; this._adapteef = adapteef; } public void Write(string info) { _adapteed.WriteLog(info); _adapteef.WriteLog(info); } }
調用:
/// <summary> /// 對象適配器模式(Adapter Pattern) /// </summary> class Program { static void Main(string[] args) { //同時寫日志到文件和數據庫 ILogTarget dbLog = new LogAdapter(new FileLog(), new DatabaseLog()); dbLog.Write("程序啟動成功"); } }
如果改用類適配器:我們難道使用這樣的寫法達到目的?
public class DatabaseLogAdapter : DatabaseLog, FileLog, ILogTarget { public void Write(string info) { this.WriteLog(info); } }
結果肯定是不能的,一個類不能具有多個基類,這樣寫明細有錯誤。所有針對不同的情況,我們應該采用合適的方式去進行適配調度。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。