【C#设计模式-适配器模式】
2016-04-26 12:48
796 查看
1.适配器模式一般的额使用情况:
在软件系统中,由于应用环境的变化,常常需要将“一些现存的对象”放在新的环境中应用。但是新环境要求的接口是这些现存对象所不满足的。如何应对这种“迁移的变化”?如何既能利用现有对象的良好实现,同时又能满足新的应用环境所要求的接口?Adapter 模式为我们很好的解决这类问题。
结构:
2.列举生活中存在的例子进行说明:
这里我们以日志记录程序为Demo说明,在任何一套软件中都会有对应的日志管理模块,假如如果我们在开发软件中的日记记录采用第三方的日志组件进行日志记录,它采用的是Log.Write("写日志");方式,我们的程序在开发中,大量实例化日记记录对象,采用的Log.Write()方式进行日志记录,但是现在第三方的日志组件现在不免费了,需要收费了,于是我们打算使用一种新的日志管理模块,只不过它提供给我们的API接口是采用Log.WriteLog("新的写日志的方式");进行日志记录。这个时候问题就出现了,如何应对这种迁移的变化呢?
先看原来日志的接口,这里采用的是Write(“写日志”);
原来写日志的方法依旧不变:Write("写日志");
上面我们添加了FileLogAdapter 类,DatabaseLogAdapter类,继承了FileLog,DatabaseLog, ILogTarget接口,重写Write方法里面调用新的写日志的方式WriteLog,使用这样的方式进行了迁移变化。下面使用对象适配:
比较两者的迁移变化,在类适配方式中,我们得到的适配器类DatabaseLogAdapter和FileLogAdapter具有它所继承的父类的所有的行为,同时也具有接口ILogTarget的所有行为,这样其实是违背了面向对象设计原则中的类的单一职责原则,而对象适配器则更符合面向对象的精神,所以在实际应用中不太推荐类适配这种方式。假设我们要适配出来的类在记录日志时同时写入文件和数据库,那么用对象适配器我们会这样去写:
结果肯定是不能的,一个类不能具有多个基类,这样写明细有错误。所有针对不同的情况,我们应该采用合适的方式去进行适配调度。
在软件系统中,由于应用环境的变化,常常需要将“一些现存的对象”放在新的环境中应用。但是新环境要求的接口是这些现存对象所不满足的。如何应对这种“迁移的变化”?如何既能利用现有对象的良好实现,同时又能满足新的应用环境所要求的接口?Adapter 模式为我们很好的解决这类问题。
结构:
2.列举生活中存在的例子进行说明:
这里我们以日志记录程序为Demo说明,在任何一套软件中都会有对应的日志管理模块,假如如果我们在开发软件中的日记记录采用第三方的日志组件进行日志记录,它采用的是Log.Write("写日志");方式,我们的程序在开发中,大量实例化日记记录对象,采用的Log.Write()方式进行日志记录,但是现在第三方的日志组件现在不免费了,需要收费了,于是我们打算使用一种新的日志管理模块,只不过它提供给我们的API接口是采用Log.WriteLog("新的写日志的方式");进行日志记录。这个时候问题就出现了,如何应对这种迁移的变化呢?
先看原来日志的接口,这里采用的是Write(“写日志”);
/// <summary> /// 原来的日志记录接口 /// </summary> public interface ILogTarget { /// <summary> /// 原来的写日志方法 /// </summary> void Write(string info); }然而现在的写日志的接口,采用的是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); } }如何使用者两个新对象中的方式,替换原来的写日志的方式呢?
/// <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); } }调用依据使用的原来写日志的方法,但是确实使用的新的写日志的方式:
/// <summary> /// 类 适配器模式(Adapter Pattern) /// </summary> class Program { static void Main(string[] args) { ILogTarget dbLog = new DatabaseLogAdapter(); dbLog.Write("程序启动成功"); dbLog = new FileLogAdapter(); dbLog.Write("程序启动成功"); } }上面的方式采用的是类适配器的方式实现了新的日志功能的迁移变化,下面我们使用对象适配器,可以区别发现两种方式的特别之处>
原来写日志的方法依旧不变:Write("写日志");
/// <summary> /// 原来的日志记录接口 /// </summary> public interface ILogTarget { /// <summary> /// 原来的写日志方法 /// </summary> void Write(string info); }现在的写日志的接口,采用的是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); } }
上面我们添加了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); } }在程序中的调用:
/// <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); } }
结果肯定是不能的,一个类不能具有多个基类,这样写明细有错误。所有针对不同的情况,我们应该采用合适的方式去进行适配调度。
相关文章推荐
- C#事件(event)的一个实例
- C#操作Xml文件:增,删,改,查
- c# 虚函数Virtual与重写override
- C#常用异常类记录
- 用于验证码图片识别的类(C#源码)
- C#索引器
- 浅谈C#垃圾回收
- 平面内,线与线 两条线找交点 两条线段的位置关系(相交)判定与交点求解 C#
- c# winform 动态画矩形 矩形大小可以拖动
- C# winform开发:Graphics、pictureBox同时画多个矩形
- C#碎碎念(一)值类型与引用类型
- C#之泛型
- C# 获取当前路径方法
- C# INI类
- C#实现XML和实体类之间相互转换:序列化和反序列化
- C#如何读写和创建INI文件
- C# 计算时间差
- C#操作XML-创建-追加-带属性的读写(全)
- C# Timer用法及实例详解
- 了解了点C#的基础知识