设计模式之四:适配器模式(Adapter Pattern)
在软件系统中,由于应用环境的变化,常常需要将“一些现存的对象”放在新的环境中应用,但是新环境要求的接口是这些现存对象所不满足的。如果能既能利用现有对象的良好实现,同时又能满足新的应用环境所要求的接口?这就是适配器模式要解决的问题。
目的:将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
下面以日志记录程序为例子说明Adapter模式。假设我们在软件开发中要记录日志,包括数据库记录日志DatabaseLog和文本文件记录日志WriteLog.现有日志接口为:
类图实现:
public abstract class Log
{
public abstract void WriteLog();
}
public class DatabaseLog : Log
{
public override void WirteLog()
{
Console.WriteLine("called database log");
}
}
public class FileLog : Log
{
public override void WirteLog()
{
Console.WriteLine("called File log");
}
}
但是开发过程需要引入一个新的日志接口,但新的日志接口和以前的不一样,该接口如下:public interface Ilog
{
void Write();
}
由于前后两个接口都不能修改,那么如何来适配前后两种情况,从而使原来的对象适应新的接口呢?
其实有两种思路:一个是类适配模式,另一个对象适配模式。类适配模式是通过类的继承机制来实现,而对象适配机制通过对象的组合来实现。
1.类适配模式类图实现:
具体实现为:
public class DatabaseLogAdapter : DatabaseLog, Ilog
{
public void Write()
{
this.WirteLog();
}
}
public class FileLogAdapter : FileLog, Ilog
{
public void Write()
{
this.WirteLog();
}
}
- 对象适配模式实现类图:
代码实现:
//对象适配
public class LogAdapter : Ilog
{
private Log log;
public LogAdapter(Log log)
{
this.log = log;
}
public void Write()
{
log.WriteLog();
}
}
上两种适配方式,可以看出在类适配方式中,是通过类的继承来实现的,同时也具有接口ILog的所有行为,这些就违背了面向对象设计原则中的类的单一职责原则,而对象适配器则是通过对象组合的方式来实现的,则符合面向对象的精神,所以推荐用对象适配的模式。
实现要点:
- Adapter模式主要应用于“希望复用一些现存的类,但是接口又与复用环境要求不一致的情况”,在代码复用,类库迁移等方面非常有用。
- Adapter模式有对象适配器和类适配器两种形式的实现结构,但是类适配器采用“多继承”的实现方式,带来了不良的高耦合,而对象适配器采用“对象组合”的方式,更符合松耦合。
- Adapter模式本身要求我们尽可能的使用“面向接口编程”风格,这样才能在后期很方便的适配。